using FFXIVClassic_Lobby_Server; using FFXIVClassic_Lobby_Server.common; using FFXIVClassic_Lobby_Server.packets; using FFXIVClassic_Map_Server.actors.area; using FFXIVClassic_Map_Server.actors.chara.player; using FFXIVClassic_Map_Server.actors.director; using FFXIVClassic_Map_Server.dataobjects; using FFXIVClassic_Map_Server.dataobjects.chara; using FFXIVClassic_Map_Server.lua; using FFXIVClassic_Map_Server.packets.send; using FFXIVClassic_Map_Server.packets.send.actor; using FFXIVClassic_Map_Server.packets.send.actor.events; using FFXIVClassic_Map_Server.packets.send.actor.inventory; using FFXIVClassic_Map_Server.packets.send.Actor.inventory; using FFXIVClassic_Map_Server.packets.send.events; using FFXIVClassic_Map_Server.packets.send.list; using FFXIVClassic_Map_Server.packets.send.login; using FFXIVClassic_Map_Server.packets.send.player; using FFXIVClassic_Map_Server.utils; using MySql.Data.MySqlClient; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace FFXIVClassic_Map_Server.Actors { 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_BSM = 30; public const int CLASSID_ARM = 31; public const int CLASSID_GSM = 32; public const int CLASSID_LTW = 33; public const int CLASSID_WVR = 34; public const int CLASSID_ALC = 35; public const int CLASSID_CUL = 36; public const int CLASSID_MIN = 39; public const int CLASSID_BTN = 40; public const int CLASSID_FSH = 41; public const int MAXSIZE_INVENTORY_NORMAL = 200; public const int MAXSIZE_INVENTORY_CURRANCY = 320; public const int MAXSIZE_INVENTORY_KEYITEMS = 500; public const int MAXSIZE_INVENTORY_LOOT = 10; public const int MAXSIZE_INVENTORY_MELDREQUEST = 4; public const int MAXSIZE_INVENTORY_BAZAAR = 10; public const int MAXSIZE_INVENTORY_EQUIPMENT = 35; public const int TIMER_TOTORAK = 0; public const int TIMER_DZEMAEL = 1; public const int TIMER_BOWL_OF_EMBERS_HARD = 2; public const int TIMER_BOWL_OF_EMBERS = 3; public const int TIMER_THORNMARCH = 4; public const int TIMER_AURUMVALE = 5; public const int TIMER_CUTTERSCRY = 6; public const int TIMER_BATTLE_ALEPORT = 7; public const int TIMER_BATTLE_HYRSTMILL = 8; public const int TIMER_BATTLE_GOLDENBAZAAR = 9; public const int TIMER_HOWLING_EYE_HARD = 10; public const int TIMER_HOWLING_EYE = 11; public const int TIMER_CASTRUM_TOWER = 12; public const int TIMER_BOWL_OF_EMBERS_EXTREME = 13; public const int TIMER_RIVENROAD = 14; public const int TIMER_RIVENROAD_HARD = 15; public const int TIMER_BEHEST = 16; public const int TIMER_COMPANYBEHEST = 17; public const int TIMER_RETURN = 18; public const int TIMER_SKIRMISH = 19; public static int[] MAXEXP = {570, 700, 880, 1100, 1500, 1800, 2300, 3200, 4300, 5000, //Level <= 10 5900, 6800, 7700, 8700, 9700, 11000, 12000, 13000, 15000, 16000, //Level <= 20 20000, 22000, 23000, 25000, 27000, 29000, 31000, 33000, 35000, 38000, //Level <= 30 45000, 47000, 50000, 53000, 56000, 59000, 62000, 65000, 68000, 71000, //Level <= 40 74000, 78000, 81000, 85000, 89000, 92000, 96000, 100000, 100000, 110000}; //Level <= 50 //Event Related public uint currentEventOwner = 0; public string currentEventName = ""; public uint currentCommand = 0; public string currentCommandName = ""; public uint eventMenuId = 0; //Player Info public uint[] timers = new uint[20]; public ushort currentJob; public uint currentTitle; public uint playTime; public uint lastPlayTimeUpdate; public bool isGM = false; public bool isZoneChanging = true; //Inventory private Dictionary inventories = new Dictionary(); private Equipment equipment; //GC Related public byte gcCurrent; public byte gcRankLimsa; public byte gcRankGridania; public byte gcRankUldah; //Mount Related public bool hasChocobo; public bool hasGoobbue; public byte chocoboAppearance; public string chocoboName; public byte mountState = 0; public uint achievementPoints; //Property Array Request Stuff private int lastPosition = 0; private int lastStep = 0; //Quest Actors (MUST MATCH playerWork.questScenario/questGuildleve) public Quest[] questScenario = new Quest[16]; public Quest[] questGuildleve = new Quest[8]; public Director currentDirector; public PlayerWork playerWork = new PlayerWork(); public ConnectedPlayer playerSession; public Player(ConnectedPlayer cp, uint actorID) : base(actorID) { playerSession = cp; actorName = String.Format("_pc{0:00000000}", actorID); className = "Player"; currentSubState = SetActorStatePacket.SUB_STATE_PLAYER; inventories[Inventory.NORMAL] = new Inventory(this, MAXSIZE_INVENTORY_NORMAL, Inventory.NORMAL); inventories[Inventory.KEYITEMS] = new Inventory(this, MAXSIZE_INVENTORY_KEYITEMS, Inventory.KEYITEMS); inventories[Inventory.CURRANCY] = new Inventory(this, MAXSIZE_INVENTORY_CURRANCY, Inventory.CURRANCY); inventories[Inventory.MELDREQUEST] = new Inventory(this, MAXSIZE_INVENTORY_MELDREQUEST, Inventory.MELDREQUEST); inventories[Inventory.BAZAAR] = new Inventory(this, MAXSIZE_INVENTORY_BAZAAR, Inventory.BAZAAR); inventories[Inventory.LOOT] = new Inventory(this, MAXSIZE_INVENTORY_LOOT, Inventory.LOOT); equipment = new Equipment(this, inventories[Inventory.NORMAL], MAXSIZE_INVENTORY_EQUIPMENT, Inventory.EQUIPMENT); //Set the Skill level caps of all FFXIV (classes)skills to 50 for (int i = 0; i < charaWork.battleSave.skillLevelCap.Length; i++) { if (i != CLASSID_PUG && i != CLASSID_MRD && i != CLASSID_GLA && i != CLASSID_MRD && i != CLASSID_ARC && i != CLASSID_LNC && i != CLASSID_THM && i != CLASSID_CNJ && i != CLASSID_CRP && i != CLASSID_BSM && i != CLASSID_ARM && i != CLASSID_GSM && i != CLASSID_LTW && i != CLASSID_WVR && i != CLASSID_ALC && i != CLASSID_CUL && i != CLASSID_MIN && i != CLASSID_BTN && i != CLASSID_FSH) charaWork.battleSave.skillLevelCap[i] = 0xFF; else charaWork.battleSave.skillLevelCap[i] = 50; } charaWork.property[0] = 1; charaWork.property[1] = 1; charaWork.property[2] = 1; charaWork.property[4] = 1; charaWork.command[0] = 0xA0F00000 | 21001; charaWork.command[1] = 0xA0F00000 | 21001; charaWork.command[2] = 0xA0F00000 | 21002; charaWork.command[3] = 0xA0F00000 | 12004; charaWork.command[4] = 0xA0F00000 | 21005; charaWork.command[5] = 0xA0F00000 | 21006; charaWork.command[6] = 0xA0F00000 | 21007; charaWork.command[7] = 0xA0F00000 | 12009; charaWork.command[8] = 0xA0F00000 | 12010; charaWork.command[9] = 0xA0F00000 | 12005; charaWork.command[10] = 0xA0F00000 | 12007; charaWork.command[11] = 0xA0F00000 | 12011; charaWork.command[12] = 0xA0F00000 | 22012; charaWork.command[13] = 0xA0F00000 | 22013; charaWork.command[14] = 0xA0F00000 | 29497; charaWork.command[15] = 0xA0F00000 | 22015; charaWork.command[32] = 0xA0F00000 | 27191; charaWork.command[33] = 0xA0F00000 | 22302; charaWork.command[34] = 0xA0F00000 | 28466; charaWork.commandAcquired[27150 - 26000] = true; playerWork.questScenarioComplete[110001 - 110001] = true; playerWork.questGuildleveComplete[120050 - 120001] = true; for (int i = 0; i < charaWork.additionalCommandAcquired.Length; i++ ) charaWork.additionalCommandAcquired[i] = true; for (int i = 0; i < charaWork.commandCategory.Length; i++) charaWork.commandCategory[i] = 1; charaWork.battleTemp.generalParameter[3] = 1; charaWork.eventSave.bazaarTax = 5; charaWork.battleSave.potencial = 6.6f; charaWork.commandCategory[0] = 1; charaWork.commandCategory[1] = 1; charaWork.commandCategory[32] = 1; charaWork.commandCategory[33] = 1; charaWork.commandCategory[34] = 1; charaWork.parameterSave.commandSlot_compatibility[0] = true; charaWork.parameterSave.commandSlot_compatibility[1] = true; charaWork.parameterSave.commandSlot_compatibility[32] = true; charaWork.commandBorder = 0x20; charaWork.parameterTemp.tp = 3000; Database.loadPlayerCharacter(this); lastPlayTimeUpdate = Utils.UnixTimeStampUTC(); } public List create0x132Packets(uint playerActorId) { List packets = new List(); packets.Add(_0x132Packet.buildPacket(playerActorId, 0xB, "commandForced")); packets.Add(_0x132Packet.buildPacket(playerActorId, 0xA, "commandDefault")); packets.Add(_0x132Packet.buildPacket(playerActorId, 0x6, "commandWeak")); packets.Add(_0x132Packet.buildPacket(playerActorId, 0x4, "commandContent")); packets.Add(_0x132Packet.buildPacket(playerActorId, 0x6, "commandJudgeMode")); packets.Add(_0x132Packet.buildPacket(playerActorId, 0x100, "commandRequest")); packets.Add(_0x132Packet.buildPacket(playerActorId, 0x100, "widgetCreate")); packets.Add(_0x132Packet.buildPacket(playerActorId, 0x100, "macroRequest")); return packets; } public override SubPacket createScriptBindPacket(uint playerActorId) { List lParams; if (isMyPlayer(playerActorId)) { if (currentDirector != null) lParams = LuaUtils.createLuaParamList("/Chara/Player/Player_work", false, false, true, currentDirector, true, 0, false, timers, true); else lParams = LuaUtils.createLuaParamList("/Chara/Player/Player_work", false, false, false, true, 0, false, timers, true); } else lParams = LuaUtils.createLuaParamList("/Chara/Player/Player_work", false, false, false, false, false, true); return ActorInstantiatePacket.buildPacket(actorId, playerActorId, actorName, className, lParams); } public override BasePacket getSpawnPackets(uint playerActorId, uint spawnType) { List subpackets = new List(); subpackets.Add(createAddActorPacket(playerActorId, 8)); if (isMyPlayer(playerActorId)) subpackets.AddRange(create0x132Packets(playerActorId)); subpackets.Add(createSpeedPacket(playerActorId)); subpackets.Add(createSpawnPositonPacket(playerActorId, spawnType)); subpackets.Add(createAppearancePacket(playerActorId)); subpackets.Add(createNamePacket(playerActorId)); subpackets.Add(_0xFPacket.buildPacket(playerActorId, playerActorId)); subpackets.Add(createStatePacket(playerActorId)); subpackets.Add(createIdleAnimationPacket(playerActorId)); subpackets.Add(createInitStatusPacket(playerActorId)); subpackets.Add(createSetActorIconPacket(playerActorId)); subpackets.Add(createIsZoneingPacket(playerActorId)); subpackets.AddRange(createPlayerRelatedPackets(playerActorId)); subpackets.Add(createScriptBindPacket(playerActorId)); return BasePacket.createPacket(subpackets, true, false); } public List createPlayerRelatedPackets(uint playerActorId) { List subpackets = new List(); if (gcCurrent != 0) subpackets.Add(SetGrandCompanyPacket.buildPacket(actorId, playerActorId, gcCurrent, gcRankLimsa, gcRankGridania, gcRankUldah)); if (currentTitle != 0) subpackets.Add(SetPlayerTitlePacket.buildPacket(actorId, playerActorId, currentTitle)); if (currentJob != 0) subpackets.Add(SetCurrentJobPacket.buildPacket(actorId, playerActorId, currentJob)); if (isMyPlayer(playerActorId)) { subpackets.Add(_0x196Packet.buildPacket(playerActorId, playerActorId)); if (hasChocobo && chocoboName != null && !chocoboName.Equals("")) { subpackets.Add(SetChocoboNamePacket.buildPacket(actorId, playerActorId, chocoboName)); subpackets.Add(SetHasChocoboPacket.buildPacket(playerActorId, hasChocobo)); } if (hasGoobbue) subpackets.Add(SetHasGoobbuePacket.buildPacket(playerActorId, hasGoobbue)); subpackets.Add(SetAchievementPointsPacket.buildPacket(playerActorId, achievementPoints)); subpackets.Add(Database.getLatestAchievements(this)); subpackets.Add(Database.getAchievementsPacket(this)); } return subpackets; } public override BasePacket getInitPackets(uint playerActorId) { ActorPropertyPacketUtil propPacketUtil = new ActorPropertyPacketUtil("/_init", this, playerActorId); propPacketUtil.addProperty("charaWork.eventSave.bazaarTax"); 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"); propPacketUtil.addProperty("charaWork.parameterSave.state_mainSkill[0]"); 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("charaWork.battleTemp.castGauge_speed[0]"); propPacketUtil.addProperty("charaWork.battleTemp.castGauge_speed[1]"); //Battle Save Skillpoint //Commands propPacketUtil.addProperty("charaWork.commandBorder"); for (int i = 0; i < charaWork.command.Length; i++) { if (charaWork.command[i] != 0) propPacketUtil.addProperty(String.Format("charaWork.command[{0}]", i)); } for (int i = 0; i < charaWork.commandCategory.Length; i++) { charaWork.commandCategory[i] = 1; if (charaWork.commandCategory[i] != 0) propPacketUtil.addProperty(String.Format("charaWork.commandCategory[{0}]", i)); } for (int i = 0; i < charaWork.commandAcquired.Length; i++) { if (charaWork.commandAcquired[i] != false) propPacketUtil.addProperty(String.Format("charaWork.commandAcquired[{0}]", i)); } for (int i = 0; i < charaWork.additionalCommandAcquired.Length; i++) { if (charaWork.additionalCommandAcquired[i] != false) propPacketUtil.addProperty(String.Format("charaWork.additionalCommandAcquired[{0}]", i)); } for (int i = 0; i < charaWork.parameterSave.commandSlot_compatibility.Length; i++) { charaWork.parameterSave.commandSlot_compatibility[i] = true; if (charaWork.parameterSave.commandSlot_compatibility[i]) propPacketUtil.addProperty(String.Format("charaWork.parameterSave.commandSlot_compatibility[{0}]", i)); } /* for (int i = 0; i < charaWork.parameterSave.commandSlot_recastTime.Length; i++) { if (charaWork.parameterSave.commandSlot_recastTime[i] != 0) propPacketUtil.addProperty(String.Format("charaWork.parameterSave.commandSlot_recastTime[{0}]", i)); } */ //System propPacketUtil.addProperty("charaWork.parameterTemp.forceControl_float_forClientSelf[0]"); propPacketUtil.addProperty("charaWork.parameterTemp.forceControl_float_forClientSelf[1]"); propPacketUtil.addProperty("charaWork.parameterTemp.forceControl_int16_forClientSelf[0]"); propPacketUtil.addProperty("charaWork.parameterTemp.forceControl_int16_forClientSelf[1]"); charaWork.parameterTemp.otherClassAbilityCount[0] = 4; charaWork.parameterTemp.otherClassAbilityCount[1] = 5; charaWork.parameterTemp.giftCount[1] = 5; propPacketUtil.addProperty("charaWork.parameterTemp.otherClassAbilityCount[0]"); propPacketUtil.addProperty("charaWork.parameterTemp.otherClassAbilityCount[1]"); propPacketUtil.addProperty("charaWork.parameterTemp.giftCount[1]"); propPacketUtil.addProperty("charaWork.depictionJudge"); //Scenario for (int i = 0; i < playerWork.questScenario.Length; i++) { if (playerWork.questScenario[i] != 0) propPacketUtil.addProperty(String.Format("playerWork.questScenario[{0}]", i)); } //Guildleve - Local for (int i = 0; i < playerWork.questGuildleve.Length; i++) { if (playerWork.questGuildleve[i] != 0) propPacketUtil.addProperty(String.Format("playerWork.questGuildleve[{0}]", i)); } //Guildleve - Regional for (int i = 0; i < work.guildleveId.Length; i++) { if (work.guildleveId[i] != 0) propPacketUtil.addProperty(String.Format("work.guildleveId[{0}]", i)); if (work.guildleveDone[i] != false) propPacketUtil.addProperty(String.Format("work.guildleveDone[{0}]", i)); if (work.guildleveChecked[i] != false) propPacketUtil.addProperty(String.Format("work.guildleveChecked[{0}]", i)); } //NPC Linkshell for (int i = 0; i < playerWork.npcLinkshellChatCalling.Length; i++) { if (playerWork.npcLinkshellChatCalling[i] != false) propPacketUtil.addProperty(String.Format("playerWork.npcLinkshellChatCalling[{0}]", i)); if (playerWork.npcLinkshellChatExtra[i] != false) propPacketUtil.addProperty(String.Format("playerWork.npcLinkshellChatExtra[{0}]", i)); } propPacketUtil.addProperty("playerWork.restBonusExpRate"); //Profile propPacketUtil.addProperty("playerWork.tribe"); propPacketUtil.addProperty("playerWork.guardian"); propPacketUtil.addProperty("playerWork.birthdayMonth"); propPacketUtil.addProperty("playerWork.birthdayDay"); propPacketUtil.addProperty("playerWork.initialTown"); return BasePacket.createPacket(propPacketUtil.done(), true, false); } public void sendZoneInPackets(WorldManager world, ushort spawnType) { queuePacket(SetActorIsZoningPacket.buildPacket(actorId, actorId, false)); queuePacket(_0x10Packet.buildPacket(actorId, 0xFF)); queuePacket(SetMusicPacket.buildPacket(actorId, zone.bgmDay, 0x01)); queuePacket(SetWeatherPacket.buildPacket(actorId, SetWeatherPacket.WEATHER_CLEAR)); queuePacket(SetMapPacket.buildPacket(actorId, zone.regionId, zone.actorId)); queuePacket(getSpawnPackets(actorId, spawnType)); getSpawnPackets(actorId, spawnType).debugPrintPacket(); #region grouptest //Retainers List retainerListEntries = new List(); retainerListEntries.Add(new ListEntry(actorId, 0xFFFFFFFF, 0x139E, false, true, customDisplayName)); retainerListEntries.Add(new ListEntry(0x23, 0x0, 0xFFFFFFFF, false, false, "TEST1")); retainerListEntries.Add(new ListEntry(0x24, 0x0, 0xFFFFFFFF, false, false, "TEST2")); retainerListEntries.Add(new ListEntry(0x25, 0x0, 0xFFFFFFFF, false, false, "TEST3")); BasePacket retainerListPacket = BasePacket.createPacket(ListUtils.createRetainerList(actorId, 0xF4, 1, 0x800000000004e639, retainerListEntries), true, false); playerSession.queuePacket(retainerListPacket); //Party List partyListEntries = new List(); partyListEntries.Add(new ListEntry(actorId, 0xFFFFFFFF, 0xFFFFFFFF, false, true, customDisplayName)); partyListEntries.Add(new ListEntry(0x029B27D3, 0xFFFFFFFF, 0x195, false, true, "Valentine Bluefeather")); BasePacket partyListPacket = BasePacket.createPacket(ListUtils.createPartyList(actorId, 0xF4, 1, 0x8000000000696df2, partyListEntries), true, false); playerSession.queuePacket(partyListPacket); #endregion #region Inventory & Equipment queuePacket(InventoryBeginChangePacket.buildPacket(actorId)); inventories[Inventory.NORMAL].sendFullInventory(); inventories[Inventory.CURRANCY].sendFullInventory(); inventories[Inventory.KEYITEMS].sendFullInventory(); inventories[Inventory.BAZAAR].sendFullInventory(); inventories[Inventory.MELDREQUEST].sendFullInventory(); inventories[Inventory.LOOT].sendFullInventory(); equipment.SendFullEquipment(false); playerSession.queuePacket(InventoryEndChangePacket.buildPacket(actorId), true, false); #endregion playerSession.queuePacket(getInitPackets(actorId)); BasePacket areaMasterSpawn = zone.getSpawnPackets(actorId); BasePacket debugSpawn = world.GetDebugActor().getSpawnPackets(actorId); BasePacket worldMasterSpawn = world.GetActor().getSpawnPackets(actorId); BasePacket directorSpawn = null; if (currentDirector != null) directorSpawn = currentDirector.getSpawnPackets(actorId); playerSession.queuePacket(areaMasterSpawn); playerSession.queuePacket(debugSpawn); if (directorSpawn != null) { //directorSpawn.debugPrintPacket(); // currentDirector.getInitPackets(actorId).debugPrintPacket(); queuePacket(directorSpawn); queuePacket(currentDirector.getInitPackets(actorId)); //queuePacket(currentDirector.getSetEventStatusPackets(actorId)); } playerSession.queuePacket(worldMasterSpawn); if (zone.isInn) { SetCutsceneBookPacket cutsceneBookPacket = new SetCutsceneBookPacket(); for (int i = 0; i < 2048; i++) cutsceneBookPacket.cutsceneFlags[i] = true; SubPacket packet = cutsceneBookPacket.buildPacket(actorId, "", 11, 1, 1); packet.debugPrintSubPacket(); queuePacket(packet); } #region hardcode BasePacket reply10 = new BasePacket("./packets/login/login10.bin"); //Item Storage, Inn Door created BasePacket reply11 = new BasePacket("./packets/login/login11.bin"); //NPC Create ??? Final init reply10.replaceActorID(actorId); reply11.replaceActorID(actorId); //playerSession.queuePacket(reply10); // playerSession.queuePacket(reply11); #endregion } private void sendRemoveInventoryPackets(List slots) { int currentIndex = 0; while (true) { if (slots.Count - currentIndex >= 64) queuePacket(InventoryRemoveX64Packet.buildPacket(actorId, slots, ref currentIndex)); else if (slots.Count - currentIndex >= 32) queuePacket(InventoryRemoveX32Packet.buildPacket(actorId, slots, ref currentIndex)); else if (slots.Count - currentIndex >= 16) queuePacket(InventoryRemoveX16Packet.buildPacket(actorId, slots, ref currentIndex)); else if (slots.Count - currentIndex >= 8) queuePacket(InventoryRemoveX08Packet.buildPacket(actorId, slots, ref currentIndex)); else if (slots.Count - currentIndex == 1) queuePacket(InventoryRemoveX01Packet.buildPacket(actorId, slots[currentIndex])); else break; } } public bool isMyPlayer(uint otherActorId) { return actorId == otherActorId; } public void queuePacket(BasePacket packet) { playerSession.queuePacket(packet); } public void queuePacket(SubPacket packet) { playerSession.queuePacket(packet, true, false); } public void queuePackets(List packets) { foreach (SubPacket subpacket in packets) playerSession.queuePacket(subpacket, true, false); } public void broadcastPacket(SubPacket packet, bool sendToSelf) { if (sendToSelf) queuePacket(packet); foreach (Actor a in playerSession.actorInstanceList) { if (a is Player) { Player p = (Player)a; SubPacket clonedPacket = new SubPacket(packet, a.actorId); p.queuePacket(clonedPacket); } } } public void setDCFlag(bool flag) { if (flag) { broadcastPacket(SetActorIconPacket.buildPacket(actorId, actorId, SetActorIconPacket.DISCONNECTING), true); } else { if (isGM) broadcastPacket(SetActorIconPacket.buildPacket(actorId, actorId, SetActorIconPacket.ISGM), true); else broadcastPacket(SetActorIconPacket.buildPacket(actorId, actorId, 0), true); } } public void cleanupAndSave() { //Remove actor from zone and main server list zone.removeActorFromZone(this); Server.getServer().removePlayer(this); //Save Player Database.savePlayerPlayTime(this); Database.savePlayerPosition(this); Log.info(String.Format("{0} has been logged out and saved.", this.customDisplayName)); } public Area getZone() { return zone; } public void sendMessage(uint logType, string sender, string message) { queuePacket(SendMessagePacket.buildPacket(actorId, actorId, logType, sender, message)); } public void logout() { queuePacket(LogoutPacket.buildPacket(actorId)); cleanupAndSave(); } public void quitGame() { queuePacket(QuitPacket.buildPacket(actorId)); cleanupAndSave(); } public uint getPlayTime(bool doUpdate) { if (doUpdate) { uint curTime = Utils.UnixTimeStampUTC(); playTime += curTime - lastPlayTimeUpdate; lastPlayTimeUpdate = curTime; } return playTime; } public void changeMusic(ushort musicId) { queuePacket(SetMusicPacket.buildPacket(actorId, musicId, 1)); } public void sendChocoboAppearance() { broadcastPacket(SetCurrentMountChocoboPacket.buildPacket(actorId, chocoboAppearance), true); } public void sendGoobbueAppearance() { broadcastPacket(SetCurrentMountGoobbuePacket.buildPacket(actorId, 1), true); } public void setMountState(byte mountState) { this.mountState = mountState; } public byte getMountState() { return mountState; } public void doEmote(uint emoteId) { broadcastPacket(ActorDoEmotePacket.buildPacket(actorId, actorId, currentTarget, emoteId), true); } public void sendGameMessage(Actor sourceActor, Actor textIdOwner, ushort textId, byte log, params object[] msgParams) { if (msgParams.Length == 0) { queuePacket(GameMessagePacket.buildPacket(Server.GetWorldManager().GetActor().actorId, actorId, sourceActor.actorId, textIdOwner.actorId, textId, log)); } else queuePacket(GameMessagePacket.buildPacket(Server.GetWorldManager().GetActor().actorId, actorId, sourceActor.actorId, textIdOwner.actorId, textId, log, LuaUtils.createLuaParamList(msgParams))); } public void sendGameMessage(Actor textIdOwner, ushort textId, byte log, params object[] msgParams) { if (msgParams.Length == 0) queuePacket(GameMessagePacket.buildPacket(Server.GetWorldManager().GetActor().actorId, actorId, textIdOwner.actorId, textId, log)); else queuePacket(GameMessagePacket.buildPacket(Server.GetWorldManager().GetActor().actorId, actorId, textIdOwner.actorId, textId, log, LuaUtils.createLuaParamList(msgParams))); } public void sendGameMessage(Actor textIdOwner, ushort textId, byte log, string customSender, params object[] msgParams) { if (msgParams.Length == 0) queuePacket(GameMessagePacket.buildPacket(Server.GetWorldManager().GetActor().actorId, actorId, textIdOwner.actorId, textId, customSender, log)); else queuePacket(GameMessagePacket.buildPacket(Server.GetWorldManager().GetActor().actorId, actorId, textIdOwner.actorId, textId, customSender, log, LuaUtils.createLuaParamList(msgParams))); } public void sendGameMessage(Actor textIdOwner, ushort textId, byte log, uint displayId, params object[] msgParams) { if (msgParams.Length == 0) queuePacket(GameMessagePacket.buildPacket(Server.GetWorldManager().GetActor().actorId, actorId, textIdOwner.actorId, textId, displayId, log)); else queuePacket(GameMessagePacket.buildPacket(Server.GetWorldManager().GetActor().actorId, actorId, textIdOwner.actorId, textId, displayId, log, LuaUtils.createLuaParamList(msgParams))); } public void broadcastWorldMessage(ushort worldMasterId, params object[] msgParams) { //SubPacket worldMasterMessage = //zone.broadcastPacketAroundActor(this, worldMasterMessage); } public void graphicChange(uint slot, uint graphicId) { appearanceIds[slot] = graphicId; } public void graphicChange(uint slot, uint weapId, uint equipId, uint variantId, uint colorId) { uint mixedVariantId; if (weapId == 0) mixedVariantId = ((variantId & 0x1F) << 5) | colorId; else mixedVariantId = variantId; uint graphicId = (weapId & 0x3FF) << 20 | (equipId & 0x3FF) << 10 | (mixedVariantId & 0x3FF); appearanceIds[slot] = graphicId; } public void sendAppearance() { broadcastPacket(createAppearancePacket(actorId), true); } public void sendCharaExpInfo() { if (lastStep == 0) { int maxLength; if ((sizeof(short) * charaWork.battleSave.skillLevel.Length)-lastPosition < 0x5E) maxLength = (sizeof(short) * charaWork.battleSave.skillLevel.Length) - lastPosition; else maxLength = 0x5E; byte[] skillLevelBuffer = new byte[maxLength]; Buffer.BlockCopy(charaWork.battleSave.skillLevel, 0, skillLevelBuffer, 0, skillLevelBuffer.Length); SetActorPropetyPacket charaInfo1 = new SetActorPropetyPacket("charaWork/exp"); charaInfo1.setIsArrayMode(true); if (maxLength == 0x5E) { charaInfo1.addBuffer(Utils.MurmurHash2("charaWork.battleSave.skillLevel", 0), skillLevelBuffer, 0, skillLevelBuffer.Length, 0x0); lastPosition += maxLength; } else { charaInfo1.addBuffer(Utils.MurmurHash2("charaWork.battleSave.skillLevel", 0), skillLevelBuffer, 0, skillLevelBuffer.Length, 0x3); lastPosition = 0; lastStep++; } charaInfo1.addTarget(); queuePacket(charaInfo1.buildPacket(actorId, actorId)); } else if (lastStep == 1) { int maxLength; if ((sizeof(short) * charaWork.battleSave.skillLevelCap.Length) - lastPosition < 0x5E) maxLength = (sizeof(short) * charaWork.battleSave.skillLevelCap.Length) - lastPosition; else maxLength = 0x5E; byte[] skillCapBuffer = new byte[maxLength]; Buffer.BlockCopy(charaWork.battleSave.skillLevelCap, lastPosition, skillCapBuffer, 0, skillCapBuffer.Length); SetActorPropetyPacket charaInfo1 = new SetActorPropetyPacket("charaWork/exp"); if (maxLength == 0x5E) { charaInfo1.setIsArrayMode(true); charaInfo1.addBuffer(Utils.MurmurHash2("charaWork.battleSave.skillLevelCap", 0), skillCapBuffer, 0, skillCapBuffer.Length, 0x1); lastPosition += maxLength; } else { charaInfo1.setIsArrayMode(false); charaInfo1.addBuffer(Utils.MurmurHash2("charaWork.battleSave.skillLevelCap", 0), skillCapBuffer, 0, skillCapBuffer.Length, 0x3); lastStep = 0; lastPosition = 0; } charaInfo1.addTarget(); queuePacket(charaInfo1.buildPacket(actorId, actorId)); } } public InventoryItem[] getGearset(ushort classId) { return Database.getEquipment(this, classId); } public void prepareClassChange(byte classId) { //If new class, init abilties and level sendCharaExpInfo(); } public void doClassChange(byte classId) { //load hotbars //Calculate stats //Calculate hp/mp //Get Potenciel ?????? //Set HP/MP/TP PARAMS //Set mainskill and level //Set Parameters //Set current EXP //Set Hotbar Commands 1 //Set Hotbar Commands 2 //Set Hotbar Commands 3 //Check if bonus point available... set //Set rested EXP charaWork.parameterSave.state_mainSkill[0] = classId; charaWork.parameterSave.state_mainSkillLevel = charaWork.battleSave.skillLevel[classId-1]; playerWork.restBonusExpRate = 0.0f; ActorPropertyPacketUtil propertyBuilder = new ActorPropertyPacketUtil("charaWork/stateForAll", this, actorId); propertyBuilder.addProperty("charaWork.parameterSave.state_mainSkill[0]"); propertyBuilder.addProperty("charaWork.parameterSave.state_mainSkillLevel"); propertyBuilder.newTarget("playerWork/expBonus"); propertyBuilder.addProperty("playerWork.restBonusExpRate"); List packets = propertyBuilder.done(); foreach (SubPacket packet in packets) broadcastPacket(packet, true); Database.savePlayerCurrentClass(this); } public void graphicChange(int slot, InventoryItem invItem) { if (invItem == null) appearanceIds[slot] = 0; else { Item item = Server.getItemGamedata(invItem.itemId); if (item is EquipmentItem) { EquipmentItem eqItem = (EquipmentItem)item; uint mixedVariantId; if (eqItem.graphicsWeaponId == 0) mixedVariantId = ((eqItem.graphicsVariantId & 0x1F) << 5) | eqItem.graphicsColorId; else mixedVariantId = eqItem.graphicsVariantId; uint graphicId = (eqItem.graphicsWeaponId & 0x3FF) << 20 | (eqItem.graphicsEquipmentId & 0x3FF) << 10 | (mixedVariantId & 0x3FF); appearanceIds[slot] = graphicId; } } Database.savePlayerAppearance(this); broadcastPacket(createAppearancePacket(actorId), true); } public Inventory getInventory(ushort type) { if (inventories.ContainsKey(type)) return inventories[type]; else return null; } public Actor getActorInInstance(uint actorId) { foreach (Actor a in playerSession.actorInstanceList) { if (a.actorId == actorId) return a; } return null; } public void setZoneChanging(bool flag) { isZoneChanging = flag; } public bool isInZoneChange() { return isZoneChanging; } public Equipment getEquipment() { return equipment; } public Quest getQuest(uint id) { for (int i = 0; i < questScenario.Length; i++) { if (questScenario[i] != null && questScenario[i].actorId == (0xA0F00000 | id)) return questScenario[i]; } return null; } public Quest getQuest(string name) { for (int i = 0; i < questScenario.Length; i++) { if (questScenario[i] != null && questScenario[i].actorName.ToLower().Equals(name.ToLower())) return questScenario[i]; } return null; } public bool hasQuest(string name) { for (int i = 0; i < questScenario.Length; i++) { if (questScenario[i] != null && questScenario[i].actorName.ToLower().Equals(name.ToLower())) return true; } return false; } public bool hasQuest(uint id) { for (int i = 0; i < questScenario.Length; i++) { if (questScenario[i] != null && questScenario[i].actorId == (0xA0F00000 | id)) return true; } return false; } public int getQuestSlot(uint id) { for (int i = 0; i < questScenario.Length; i++) { if (questScenario[i] != null && questScenario[i].actorId == (0xA0F00000 | id)) return i; } return -1; } public void setDirector(string directorType, bool sendPackets) { if (directorType.Equals("openingDirector")) { currentDirector = new OpeningDirector(this, 0x46080012); } else if (directorType.Equals("QuestDirectorMan0l001")) { currentDirector = new QuestDirectorMan0l001(this, 0x46080012); } if (sendPackets) { queuePacket(RemoveActorPacket.buildPacket(actorId, 0x46080012)); queuePacket(currentDirector.getSpawnPackets(actorId)); queuePacket(currentDirector.getInitPackets(actorId)); //queuePacket(currentDirector.getSetEventStatusPackets(actorId)); //currentDirector.getSpawnPackets(actorId).debugPrintPacket(); //currentDirector.getInitPackets(actorId).debugPrintPacket(); } } public Director getDirector() { return currentDirector; } public void examinePlayer(Actor examinee) { Player toBeExamined; if (examinee is Player) toBeExamined = (Player)examinee; else return; queuePacket(InventoryBeginChangePacket.buildPacket(toBeExamined.actorId, actorId)); toBeExamined.getEquipment().SendCheckEquipmentToPlayer(this); queuePacket(InventoryEndChangePacket.buildPacket(toBeExamined.actorId, actorId)); } public void sendRequestedInfo(params object[] parameters) { List lParams = LuaUtils.createLuaParamList(parameters); SubPacket spacket = InfoRequestResponsePacket.buildPacket(actorId, actorId, lParams); spacket.debugPrintSubPacket(); queuePacket(spacket); } public void kickEvent(Actor actor, string conditionName, params object[] parameters) { if (actor == null) return; List lParams = LuaUtils.createLuaParamList(parameters); SubPacket spacket = KickEventPacket.buildPacket(actorId, actor.actorId, conditionName, lParams); spacket.debugPrintSubPacket(); queuePacket(spacket); } public void setEventStatus(Actor actor, string conditionName, bool enabled, byte unknown) { queuePacket(SetEventStatus.buildPacket(actorId, actor.actorId, enabled, unknown, conditionName)); } public void runEventFunction(string functionName, params object[] parameters) { List lParams = LuaUtils.createLuaParamList(parameters); SubPacket spacket = RunEventFunctionPacket.buildPacket(actorId, currentEventOwner, currentEventName, functionName, lParams); spacket.debugPrintSubPacket(); queuePacket(spacket); } public void endEvent() { SubPacket p = EndEventPacket.buildPacket(actorId, currentEventOwner, currentEventName); p.debugPrintSubPacket(); queuePacket(p); currentEventOwner = 0; currentEventName = ""; eventMenuId = 0; } public void endCommand() { SubPacket p = EndEventPacket.buildPacket(actorId, currentCommand, currentCommandName); p.debugPrintSubPacket(); queuePacket(p); currentCommand = 0; currentCommandName = ""; } public void setCurrentMenuId(uint id) { eventMenuId = id; } public uint getCurrentMenuId() { return eventMenuId; } public void sendInstanceUpdate() { //Update Instance playerSession.updateInstance(zone.getActorsAroundActor(this, 50)); } } }