// Copyright © 2017-2018 Atomic Software, LLC. All Rights Reserved. // See LICENSE.md for full license information. using Atom.Core; using Atom.Core.Diagnostics; using Atom.Core.Game.GameObjects.Characters; using Atom.Core.Game.GameObjects.Items; using Atom.Core.Game.Quests; using Atom.Core.Game.Tutorial; using Atom.Core.Mathematics; using Atom.Core.Networking; using Atom.Core.Networking.Messages.Structures.Avatar; using Atom.Core.SQL; using System; using System.IO; using System.Linq; using Atom.Core.Game; namespace Atom.WorldManagerServer.Services { internal static class CharacterService { internal static bool LoadCharacter(int nCharNo, out SimpleCharacter Character) { Character = new SimpleCharacter { CharNo = nCharNo }; return GetLoginData(Character) && GetEquippedItems(Character); } internal static bool GetLoginData(SimpleCharacter Character) { using (var p_Char_GetLoginData = new StoredProcedure("p_Char_GetLoginData", Program.ServerInstance.ODBCConnection)) { p_Char_GetLoginData.AddParameter("nCharNo", Character.CharNo); using (var Reader = p_Char_GetLoginData.RunReader()) { if (!Reader.HasRows) { return false; } while (Reader.Read()) { Character.Name = Reader.GetString(0); Character.Level = Convert.ToByte(Reader.GetValue(1)); Character.Slot = (byte)Reader.GetValue(2); Character.MapIndx = Reader.GetString(3); Character.IsDeleted = Reader.GetBoolean(7); Character.DeletedDate = Reader.GetDateTime(8); Character.Class = (CharacterClass)(byte)Reader.GetValue(10); Character.Gender = (Gender)(byte)Reader.GetValue(11); Character.Hair = (byte)Reader.GetValue(12); Character.HairColor = (byte)Reader.GetValue(13); Character.Face = (byte)Reader.GetValue(14); Character.KQHandle = Reader.GetInt32(15); Character.KQMapIndx = Reader.GetString(16); Character.KQPosition = new Vector2(Reader.GetInt32(17), Reader.GetInt32(18)); Character.KQDate = Reader.GetDateTime(20); Character.FriendPoints = Convert.ToUInt16(Reader.GetValue(21)); Character.TutorialState = (TutorialState)Reader.GetInt32(22); Character.TutorialStep = Reader.GetByte(23); } return true; } } } internal static bool GetEquippedItems(SimpleCharacter Character) { using (var p_Item_GetListType = new StoredProcedure("p_Item_GetListType", Program.ServerInstance.ODBCConnection)) { p_Item_GetListType.AddParameter("nCharNo", Character.CharNo); p_Item_GetListType.AddParameter("nStorageType", (byte) InventoryType.EQUIPPED); using (var Reader = p_Item_GetListType.RunReader()) { if (!Reader.HasRows) { return true; } while (Reader.Read()) { var ItemSlot = (ItemSlot) (byte) Reader.GetValue(1); if (Character.EquippedItems.ContainsKey(ItemSlot)) { Log.Warning($"Character had multiple items in the same equip slot [{Character.Name}]"); Character.EquippedItems.Remove(ItemSlot); } Character.EquippedItems.Add(ItemSlot, Convert.ToUInt16(Reader.GetValue(2))); } } } return true; } internal static bool IsNameInUse(string Name) { using (var p_Char_Find = new StoredProcedure("p_Char_Find", Program.ServerInstance.ODBCConnection)) { p_Char_Find.AddParameter("sID", Name, 40); p_Char_Find.AddOutput("nCharNo"); var CharNo = p_Char_Find.Run().GetOutput("nCharNo"); return CharNo != 0; } } internal static void CreateCharacter(Client Client, byte Slot, string Name, CharacterClass Class, Gender Gender, byte Hair, byte HairColor, byte Face) { int CharNo; using (var p_Char_Create = new StoredProcedure("p_Char_Create", Program.ServerInstance.ODBCConnection)) { p_Char_Create.AddParameter("nUserNo", Client.Account.UserNo); p_Char_Create.AddParameter("nCreateWorld", Program.ServerInstance.Config.GetInt32("SERVER", "Number")); p_Char_Create.AddParameter("nAdminLevel", 0); p_Char_Create.AddParameter("nSlotNo", Slot); p_Char_Create.AddParameter("sID", Name, 40); p_Char_Create.AddParameter("nRace", 1); p_Char_Create.AddParameter("nClass", (byte) Class); p_Char_Create.AddParameter("nGender", (byte) Gender); p_Char_Create.AddParameter("nHairType", Hair); p_Char_Create.AddParameter("nHairColor", HairColor); p_Char_Create.AddParameter("nFaceShape", Face); p_Char_Create.AddOutput("nCharNo"); CharNo = p_Char_Create.Run().GetOutput("nCharNo"); if (CharNo <= -1) { new PROTO_NC_AVATAR_CREATEFAIL_ACK(CreateCharacterFailedErrorCode.FAILED_CREATE).Send(Client); return; } } if (Program.DefaultCharacterData.TryGetValue(Class, out SimpleCharacter DefaultValues)) { using (var p_Char_CreateSetDefaultData = new StoredProcedure("p_Char_CreateSetDefaultData", Program.ServerInstance.ODBCConnection)) { p_Char_CreateSetDefaultData.AddParameter("nCharNo", CharNo); p_Char_CreateSetDefaultData.AddParameter("sLoginZone", DefaultValues.MapIndx, 16); p_Char_CreateSetDefaultData.AddParameter("nLoginZoneX", DefaultValues.X); p_Char_CreateSetDefaultData.AddParameter("nLoginZoneY", DefaultValues.Y); p_Char_CreateSetDefaultData.AddParameter("nHP", DefaultValues.HP); p_Char_CreateSetDefaultData.AddParameter("nSP", DefaultValues.SP); p_Char_CreateSetDefaultData.AddParameter("nHPS", DefaultValues.HPStone); p_Char_CreateSetDefaultData.AddParameter("nSPS", DefaultValues.SPStone); p_Char_CreateSetDefaultData.AddParameter("nLevel", DefaultValues.Level); p_Char_CreateSetDefaultData.AddParameter("nMoney", DefaultValues.Money); p_Char_CreateSetDefaultData.AddParameter("nExp", DefaultValues.EXP); p_Char_CreateSetDefaultData.AddOutput("nRet"); var Return = p_Char_CreateSetDefaultData.Run().GetOutput("nRet"); if (Return == 0) { new PROTO_NC_AVATAR_CREATEFAIL_ACK(CreateCharacterFailedErrorCode.FAILED_CREATE).Send(Client); return; } } using (var p_Char_RedistributePointSet = new StoredProcedure("p_Char_RedistributePointSet", Program.ServerInstance.ODBCConnection)) { p_Char_RedistributePointSet.AddParameter("nCharNo", CharNo); p_Char_RedistributePointSet.AddParameter("nSetPoint", DefaultValues.Level); p_Char_RedistributePointSet.AddOutput("nRet"); p_Char_RedistributePointSet.Run(); } foreach (var Item in DefaultValues.ItemLots.Keys) { long ItemKey; using (var p_Item_Create = new StoredProcedure("p_Item_Create", Program.ServerInstance.ODBCConnection)) { p_Item_Create.AddParameter("nOwner", CharNo); p_Item_Create.AddParameter("nStorageType", (byte) InventoryType.CHAR_INVENTORY); p_Item_Create.AddParameter("nStorage", (byte) DefaultValues.ItemLots.Keys.ToList().IndexOf(Item)); p_Item_Create.AddParameter("nItemID", (int) Item); p_Item_Create.AddParameter("nFlags", 0); p_Item_Create.AddOutput("nItemKey"); p_Item_Create.AddOutput("nRet"); ItemKey = p_Item_Create.Run().GetOutput("nItemKey"); } using (var p_Item_SetOption = new StoredProcedure("p_Item_SetOption", Program.ServerInstance.ODBCConnection)) { p_Item_SetOption.AddParameter("nItemKey", ItemKey); p_Item_SetOption.AddParameter("nOptionType", (int) ItemOptionType.IOT_NUMBER); p_Item_SetOption.AddParameter("nOptionData", DefaultValues.ItemLots[Item]); p_Item_SetOption.AddOutput("nRet"); p_Item_SetOption.Run(); } } long HouseKey; using (var p_Item_Create = new StoredProcedure("p_Item_Create", Program.ServerInstance.ODBCConnection)) { p_Item_Create.AddParameter("nOwner", CharNo); p_Item_Create.AddParameter("nStorageType", (byte) InventoryType.MINIHOUSE_SKIN); p_Item_Create.AddParameter("nStorage", 0); p_Item_Create.AddParameter("nItemID", Convert.ToInt32(31000)); p_Item_Create.AddParameter("nFlags", 0); p_Item_Create.AddOutput("nItemKey"); p_Item_Create.AddOutput("nRet"); HouseKey = p_Item_Create.Run().GetOutput("nItemKey"); } using (var p_Item_SetOption = new StoredProcedure("p_Item_SetOption", Program.ServerInstance.ODBCConnection)) { p_Item_SetOption.AddParameter("nItemKey", HouseKey); p_Item_SetOption.AddParameter("nOptionType", (int) ItemOptionType.IOT_NUMBER); p_Item_SetOption.AddParameter("nOptionData", 1); p_Item_SetOption.AddOutput("nRet"); p_Item_SetOption.Run(); } foreach (var Quest in DefaultValues.Quests) { using (var p_Quest_Add = new StoredProcedure("p_Quest_Add", Program.ServerInstance.ODBCConnection)) { p_Quest_Add.AddParameter("nCharNo", CharNo); p_Quest_Add.AddParameter("nQuestNo", Quest); p_Quest_Add.AddParameter("nStatus", (byte) QuestStatus.QS_NONE); p_Quest_Add.AddParameter("sData", new byte[100], 100); p_Quest_Add.AddOutput("nRet"); p_Quest_Add.Run(); } } foreach (var Skill in DefaultValues.Skills) { using (var p_Skill_Set = new StoredProcedure("p_Skill_Set", Program.ServerInstance.ODBCConnection)) { p_Skill_Set.AddParameter("nCharNo", CharNo); p_Skill_Set.AddParameter("nSkillNo", Convert.ToInt32(Skill)); p_Skill_Set.AddParameter("nSkillLevel", 0); p_Skill_Set.AddParameter("nSkillExp", 0); p_Skill_Set.AddParameter("nSkillWriteTime", 0); p_Skill_Set.AddParameter("nSkillCoolTime", 0); p_Skill_Set.AddParameter("nSkillPowerDemage", 0); p_Skill_Set.AddParameter("nSkillPowerSP", 0); p_Skill_Set.AddParameter("nSkillPowerKeepTime", 0); p_Skill_Set.AddParameter("nSkillPowerCoolTime", 0); p_Skill_Set.AddOutput("nRet"); p_Skill_Set.Run(); } } if (!LoadCharacter(CharNo, out SimpleCharacter Character)) { new PROTO_NC_AVATAR_CREATEFAIL_ACK(CreateCharacterFailedErrorCode.FAILED_CREATE).Send(Client); return; } Character.Shortcuts = DefaultValues.Shortcuts; Client.Account.Characters.Add(Character); new PROTO_NC_AVATAR_CREATESUCC_ACK(Client, Character).Send(Client); } else { Log.Warning($"No default character data found for {Class}"); } } internal static void LoadShortcuts(SimpleCharacter Character) { using (var p_Char_GetOptShortCutData = new StoredProcedure("p_Char_GetOptShortCutData", Program.ServerInstance.ODBCConnection)) { p_Char_GetOptShortCutData.AddParameter("nCharNo", Character.CharNo); p_Char_GetOptShortCutData.AddOutput("nRet"); p_Char_GetOptShortCutData.AddOutput("sData", 1024); p_Char_GetOptShortCutData.Run(); var Data = p_Char_GetOptShortCutData.GetOutput("sData"); using (var Stream = new MemoryStream(Data)) using (var Reader = new BinaryReader(Stream)) { var ShortcutCount = Reader.ReadUInt16(); for (var i = 0; i < ShortcutCount; i++) { var Shortcut = new Shortcut { Slot = Reader.ReadByte(), Code = Reader.ReadUInt16(), Value = Reader.ReadUInt16() }; Reader.ReadUInt16(); if (Character.Shortcuts.ContainsKey(Shortcut.Slot)) { continue; } Character.Shortcuts.Add(Shortcut.Slot, Shortcut); } } UpdateShortcutDataBinary(Character); } } internal static void SaveShortcuts(SimpleCharacter Character) { UpdateShortcutDataBinary(Character); using (var p_Char_SetOptShortCutData = new StoredProcedure("p_Char_SetOptShortCutData", Program.ServerInstance.ODBCConnection)) { p_Char_SetOptShortCutData.AddParameter("nCharNo", Character.CharNo); p_Char_SetOptShortCutData.AddParameter("sData", Character.ShortcutData, 1024); p_Char_SetOptShortCutData.AddOutput("nRet"); p_Char_SetOptShortCutData.Run(); } } internal static void UpdateShortcutDataBinary(SimpleCharacter Character) { using (var Stream = new MemoryStream()) using (var Writer = new BinaryWriter(Stream)) { Writer.Write((ushort)Character.Shortcuts.Count); foreach (var Shortcut in Character.Shortcuts.Values) { Writer.Write(Shortcut.Slot); Writer.Write(Shortcut.Code); Writer.Write(Shortcut.Value); Writer.Write((ushort)0); } Character.ShortcutData = Stream.ToArray(); } } } }