diff --git a/Database/Updates/KnownSpellsTalents.sql b/Database/Updates/KnownSpellsTalents.sql new file mode 100644 index 0000000..712e744 --- /dev/null +++ b/Database/Updates/KnownSpellsTalents.sql @@ -0,0 +1,40 @@ +SET FOREIGN_KEY_CHECKS=0; + +-- ----------------------------------------------------- +-- Table `knownspells` +-- ----------------------------------------------------- +DROP TABLE IF EXISTS `knownspells`; +CREATE TABLE `knownspells` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `spell` MEDIUMINT(8) UNSIGNED NOT NULL DEFAULT 0, + `guid` INT(11) UNSIGNED NOT NULL DEFAULT 0, + PRIMARY KEY (`id`), + INDEX `fk_knownspells_characters1_idx` (`guid` ASC), + CONSTRAINT `fk_knownspells_characters1` + FOREIGN KEY (`guid`) + REFERENCES `characters` (`guid`) + ON DELETE CASCADE + ON UPDATE CASCADE) +ENGINE = InnoDB +DEFAULT CHARACTER SET = utf8mb4; + + +-- ----------------------------------------------------- +-- Table `knowntalents` +-- ----------------------------------------------------- +DROP TABLE IF EXISTS `knowntalents`; +CREATE TABLE `knowntalents` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `talent` MEDIUMINT(8) UNSIGNED NOT NULL DEFAULT 0, + `guid` INT(11) UNSIGNED NOT NULL DEFAULT 0, + PRIMARY KEY (`id`), + INDEX `fk_knowntalents_characters1_idx` (`guid` ASC), + CONSTRAINT `fk_knowntalents_characters1` + FOREIGN KEY (`guid`) + REFERENCES `characters` (`guid`) + ON DELETE CASCADE + ON UPDATE CASCADE) +ENGINE = InnoDB +DEFAULT CHARACTER SET = utf8mb4; + +SET FOREIGN_KEY_CHECKS=1; diff --git a/WorldServer/Game/Objects/Player.cs b/WorldServer/Game/Objects/Player.cs index 646bec3..7590103 100644 --- a/WorldServer/Game/Objects/Player.cs +++ b/WorldServer/Game/Objects/Player.cs @@ -498,6 +498,39 @@ private void SetStartProfiencies() foreach (ushort spell in spellinfo) this.Spells.Add(spell, new PlayerSpell(spell)); + + //Known Spells/Talents + var knownspells = Database.KnownSpells.Values + .Where(x => x.Player == Guid) + .Select(x => x.SpellID); + + foreach (ushort spell in knownspells) + this.Spells.Add(spell, new PlayerSpell(spell)); + + var knowntalent = Database.KnownTalents.Values + .Where(x => x.Player == Guid) + .Select(x => x.TalentID); + + foreach (ushort spell in knowntalent) + this.Spells.Add(spell, new PlayerSpell(spell)); + + } + + public void ActionButtonsInitalize() + { + PacketWriter pkt = new PacketWriter(Opcodes.SMSG_ACTION_BUTTONS); + + for (var button = 0; button < 119; button++) // 119 'or 480 ? + { + var ActionBarInit = Database.CreateActionButtons.Values.Find(x => x.Button == button); + + if (ActionBarInit != null) + pkt.WriteUInt32((uint)ActionBarInit.Action | ((uint)ActionBarInit.Type << 24)); + else + pkt.WriteUInt32(0); + + this.Client.Send(pkt); + } } public void SendInitialSpells() @@ -516,6 +549,29 @@ public void SendInitialSpells() this.Client.Send(pkt); } + //Basic Factions + public void SendInitalizeFactions() + { + const int count = 0x40; + PacketWriter pkt = new PacketWriter(Opcodes.SMSG_INITIALIZE_FACTIONS); + pkt.WriteUInt32(count); + //var rep = reps[(FactionReputationIndex); + pkt.WriteUInt16((byte)2); //rep.flags + pkt.WriteUInt16(0); //rep.value + this.Client.Send(pkt); + } + + public void SendReputationStandingUpdate() + { + PacketWriter pkt = new PacketWriter(Opcodes.SMSG_SET_FACTION_STANDING); + pkt.WriteUInt32((byte)1); + pkt.WriteUInt16(0); // count (we only ever send 1) + pkt.WriteUInt16(0); //rep index + pkt.WriteUInt16(0); //rep.value + + this.Client.Send(pkt); + } + #endregion #region Visualisation Functions @@ -599,7 +655,9 @@ public void ToggleChatFlag(ChatFlags flag) public void AddActionButton(byte button, ushort action, byte type, byte misc) { ActionButton ab = new ActionButton(action, misc, type); - this.ActionButtons.Add(button, ab); + + if (this.ActionButtons.ContainsKey(button)) + this.ActionButtons.Add(button, ab); } public void RemoveActionButton(byte button) diff --git a/WorldServer/Game/Objects/UnitExtensions/SpellExtension.cs b/WorldServer/Game/Objects/UnitExtensions/SpellExtension.cs index 5261108..a095040 100644 --- a/WorldServer/Game/Objects/UnitExtensions/SpellExtension.cs +++ b/WorldServer/Game/Objects/UnitExtensions/SpellExtension.cs @@ -48,13 +48,14 @@ public static SpellCheckCastResult PrepareSpell(this Unit u, SpellCast spell) u.ChannelObject = spell.Targets.Target.Guid; GridManager.Instance.SendSurrounding(u.BuildUpdate(), u); - if (u.IsTypeOf(ObjectTypes.TYPE_PLAYER)) + //Temp Disable Channel + /*if (u.IsTypeOf(ObjectTypes.TYPE_PLAYER)) { PacketWriter channel = new PacketWriter(Opcodes.MSG_CHANNEL_START); channel.WriteUInt32(spell.Spell.Id); channel.WriteInt32(spell.Duration * 1000); ((Player)u).Client.Send(channel); - } + }*/ } return SpellCheckCastResult.SPELL_CAST_OK; } diff --git a/WorldServer/Game/Structs/PlayerStructs.cs b/WorldServer/Game/Structs/PlayerStructs.cs index 6ca6fb7..42ba1ee 100644 --- a/WorldServer/Game/Structs/PlayerStructs.cs +++ b/WorldServer/Game/Structs/PlayerStructs.cs @@ -140,6 +140,32 @@ public class LevelStatsInfo public uint Spi { get; set; } } + [Table("knownspells")] + public class KnownSpells + { + [Key] + [Column("id")] + public uint Id { get; set; } + [Column("guid")] + public ulong Player { get; set; } + + [Column("spell")] + public ushort SpellID { get; set; } + } + + [Table("knowntalents")] + public class KnownTalents + { + [Key] + [Column("id")] + public uint Id { get; set; } + [Column("guid")] + public ulong Player { get; set; } + + [Column("talent")] + public ushort TalentID { get; set; } + } + [Table("player_classlevelstats")] public class ClassLevelStat { diff --git a/WorldServer/Packets/Handlers/CharHandler.cs b/WorldServer/Packets/Handlers/CharHandler.cs index 8d32dde..5a1191a 100644 --- a/WorldServer/Packets/Handlers/CharHandler.cs +++ b/WorldServer/Packets/Handlers/CharHandler.cs @@ -7,6 +7,7 @@ using WorldServer.Game.Objects.UnitExtensions; using WorldServer.Network; using WorldServer.Storage; +using Common.Logging; namespace WorldServer.Packets.Handlers { @@ -240,15 +241,35 @@ public static void HandleRepopRequest(ref PacketReader packet, ref WorldManager public static void HandleSetActionButtonOpcode(ref PacketReader packet, ref WorldManager manager) { + Log.Message(LogType.DEBUG, "WORLD: Received opcode CMSG_SET_ACTION_BUTTON!"); byte button = packet.ReadUInt8(); ushort action = packet.ReadUInt16(); byte misc = packet.ReadUInt8(); byte type = packet.ReadUInt8(); + Log.Message(LogType.DEBUG, "BUTTON: {0} ACTION: {1} TYPE: {2}!", button, action, type); if (action == 0) + { + Log.Message(LogType.DEBUG, "MISC: Remove action from button {0}", button); manager.Character.RemoveActionButton(button); + } else + { + switch (type) + { + case (byte)ActionButtonTypes.ACTION_BUTTON_SPELL: + Log.Message(LogType.DEBUG, "MISC: Added Spell {0} into button {1}", action, button); + break; + case (byte)ActionButtonTypes.ACTION_BUTTON_ITEM: + Log.Message(LogType.DEBUG, "MISC: Added Item {0} into button {1}", action, button); + break; + default: + Log.Message(LogType.ERROR, "MISC: Unknown action button type {0} for action %u into button {1}", action, button); + return; + } + manager.Character.AddActionButton(button, action, type, misc); + } } } } diff --git a/WorldServer/Packets/Handlers/NPCHandler.cs b/WorldServer/Packets/Handlers/NPCHandler.cs index 1572549..c4a877f 100644 --- a/WorldServer/Packets/Handlers/NPCHandler.cs +++ b/WorldServer/Packets/Handlers/NPCHandler.cs @@ -10,6 +10,10 @@ using WorldServer.Game.Structs; using WorldServer.Network; using WorldServer.Storage; +using System; +using System.Collections.Generic; +using MySql.Data.MySqlClient; +using Common.Database; namespace WorldServer.Packets.Handlers { @@ -250,6 +254,10 @@ public static void HandleTrainerBuySpellOpcode(ref PacketReader packet, ref Worl ulong guid = packet.ReadUInt64(); uint spellID = packet.ReadUInt32(); + PacketWriter pkt = new PacketWriter(Opcodes.SMSG_LEARNED_SPELL); + pkt.WriteUInt32((ushort)spellID); + manager.Send(pkt); + Spell spell = null; if (!DBC.Spell.TryGetValue(spellID, out spell)) //Only use those with spells return; @@ -271,19 +279,33 @@ public static void HandleTrainerBuySpellOpcode(ref PacketReader packet, ref Worl player.Talents.Add(ability.m_ID); player.TalentPoints -= 10; - //TODO ADD SPELL TO SPELLBOOK - player.SendBuySpellSucceed(guid, spellID); manager.Character.Dirty = true; player.SendPlaySpellVisual(guid, 0xB3); - player.Spells.Add(spellID, new PlayerSpell(spell)); + //player.Spells.Add(spellID, new PlayerSpell(spell)); //TODO : Check why crash server after adding talents from here + + Console.WriteLine("Learn Talent Guid: " + player.Guid); + Console.WriteLine("Learn Talent ID: " + spellID); } break; } player.SendTalentList(); + + List columns = new List{ + "guid", "talent" + }; + + List parameters = new List + { + new MySqlParameter("@guid", player.Guid), + new MySqlParameter("@talent", spellID), + }; + + BaseContext.SaveEntity("knowntalents", columns, parameters, Globals.CONNECTION_STRING); + Database.KnownTalents.Reload(); } else if (Database.Creatures.ContainsKey(guid)) //NPC Spell purchase { @@ -307,6 +329,22 @@ public static void HandleTrainerBuySpellOpcode(ref PacketReader packet, ref Worl player.Spells.Add(spellID, new PlayerSpell(spell)); creature.SendSpellList(player); + + Console.WriteLine("Learn Player Guid: " + player.Guid); + Console.WriteLine("Learn Spell ID: " + spellID); + // TODO: 2 spells with same id crash server + List columns = new List{ + "guid", "spell" + }; + + List parameters = new List + { + new MySqlParameter("@guid", player.Guid), + new MySqlParameter("@spell", spellID), + }; + + BaseContext.SaveEntity("knownspells", columns, parameters, Globals.CONNECTION_STRING); + Database.KnownSpells.Reload(); } } diff --git a/WorldServer/Packets/Handlers/WorldHandler.cs b/WorldServer/Packets/Handlers/WorldHandler.cs index dd9017a..62b38a7 100644 --- a/WorldServer/Packets/Handlers/WorldHandler.cs +++ b/WorldServer/Packets/Handlers/WorldHandler.cs @@ -41,10 +41,11 @@ public static void HandlePlayerLogin(ref PacketReader packet, ref WorldManager m manager.Character.IsOnline = true; MiscHandler.HandleLoginSetTimespeed(ref manager); - /* - * SMSG_ACTION_BUTTONS - */ + + manager.Character.ActionButtonsInitalize(); manager.Character.SendInitialSpells(); + manager.Character.SendInitalizeFactions(); + manager.Character.SendReputationStandingUpdate(); manager.Character.SendMOTD(); manager.Character.PreLoad(); diff --git a/WorldServer/Storage/Database.cs b/WorldServer/Storage/Database.cs index 89925f7..c96f8a5 100644 --- a/WorldServer/Storage/Database.cs +++ b/WorldServer/Storage/Database.cs @@ -15,6 +15,8 @@ public static class Database { public static DbSet AreaTriggers; public static DbSet ClassLevelStats; + public static DbSet KnownSpells; + public static DbSet KnownTalents; public static DbSet CreateActionButtons; public static DbSet CreatePlayerInfo; public static DbSet CreateSkillInfo; @@ -79,6 +81,8 @@ public static void Initialize() GameObjects = new DbSet(true); Items = new DbSet(true, true); Players = new DbSet(true, true); + KnownSpells = new DbSet(false, true); + KnownTalents = new DbSet(false, true); SocialList = new GroupedDbSet>(QueryDefault + "character_social", "Social Lists", true); }