public virtual void SendUpdatePlayerSkills()
		{
			if (m_gameClient.Player == null)
				return;
			IList specs = m_gameClient.Player.GetSpecList();
			IList skills = m_gameClient.Player.GetNonTrainableSkillList();
			IList styles = m_gameClient.Player.GetStyleList();
			List<SpellLine> spelllines = m_gameClient.Player.GetSpellLines();
			var m_styleId = new Hashtable();
			int maxSkills = 0;
			int firstSkills = 0;

			var pak = new GSTCPPacketOut(GetPacketCode(eServerPackets.VariousUpdate));

			try
			{
				bool sendHybridList = m_gameClient.Player.CharacterClass.ClassType != eClassType.ListCaster;

				lock (skills.SyncRoot)
				{
					lock (styles.SyncRoot)
					{
						lock (specs.SyncRoot)
						{
							lock (m_gameClient.Player.lockSpellLinesList)
							{
								int skillCount = specs.Count + skills.Count + styles.Count;

								if (sendHybridList)
									skillCount += m_gameClient.Player.GetSpellCount();

								pak.WriteByte(0x01); //subcode
								pak.WriteByte((byte) skillCount); //number of entry
								pak.WriteByte(0x03); //subtype
								pak.WriteByte((byte) firstSkills);

								foreach (Specialization spec in specs)
								{
									CheckLengthHybridSkillsPacket(ref pak, ref maxSkills, ref firstSkills);
									pak.WriteByte((byte) spec.Level);
									pak.WriteByte((byte) eSkillPage.Specialization);
									pak.WriteShort(0);
									pak.WriteByte((byte) (m_gameClient.Player.GetModifiedSpecLevel(spec.KeyName) - spec.Level)); // bonus
									pak.WriteShort(spec.ID);
									pak.WritePascalString(spec.Name);
								}

								int i = 0;
								foreach (Skill skill in skills)
								{
									i++;
									CheckLengthHybridSkillsPacket(ref pak, ref maxSkills, ref firstSkills);
									pak.WriteByte(0);
									var type = (byte) eSkillPage.Abilities;
									if (skill is RealmAbility)
									{
										type = (byte) eSkillPage.RealmAbilities;
									}
									pak.WriteByte(type);
									pak.WriteShort(0);
									pak.WriteByte(0);
									pak.WriteShort(skill.ID);
									string str = "";
									if (m_gameClient.Player.CharacterClass.ID == (int) eCharacterClass.Vampiir)
									{
										if (skill.Name == Abilities.VampiirConstitution ||
										    skill.Name == Abilities.VampiirDexterity ||
										    skill.Name == Abilities.VampiirStrength)
											str = " +" + ((m_gameClient.Player.Level - 5)*3);
										else if (skill.Name == Abilities.VampiirQuickness)
											str = " +" + ((m_gameClient.Player.Level - 5)*2);
									}
									pak.WritePascalString(skill.Name + str);
								}

								foreach (Style style in styles)
								{
									m_styleId[(int) style.ID] = i++;
									CheckLengthHybridSkillsPacket(ref pak, ref maxSkills, ref firstSkills);
									//DOLConsole.WriteLine("style sended "+style.Name);
									pak.WriteByte(0); // no level for style
									pak.WriteByte((byte) eSkillPage.Styles);

									int pre = 0;
									switch (style.OpeningRequirementType)
									{
										case Style.eOpening.Offensive:
											pre = 0 + (int) style.AttackResultRequirement; // last result of our attack against enemy
											// hit, miss, target blocked, target parried, ...
											if (style.AttackResultRequirement == Style.eAttackResult.Style)
												pre |= ((100 + (int) m_styleId[style.OpeningRequirementValue]) << 8);
											break;
										case Style.eOpening.Defensive:
											pre = 100 + (int) style.AttackResultRequirement; // last result of enemies attack against us
											// hit, miss, you block, you parry, ...
											break;
										case Style.eOpening.Positional:
											pre = 200 + style.OpeningRequirementValue;
											break;
									}

									// style required?
									if (pre == 0)
									{
										pre = 0x100;
									}

									pak.WriteShort((ushort) pre);
									pak.WriteByte(0); // bonus
									pak.WriteShort((ushort) style.Icon);
									pak.WritePascalString(style.Name);
								}
								if (sendHybridList)
								{
									Dictionary<string, KeyValuePair<Spell, SpellLine>> spells = m_gameClient.Player.GetUsableSpells(spelllines, false);

									foreach (var spell in spells)
									{
										CheckLengthHybridSkillsPacket(ref pak, ref maxSkills, ref firstSkills);

										int spec_index = specs.IndexOf(m_gameClient.Player.GetSpecialization(spell.Value.Value.Spec));
										if (spec_index == -1)
											spec_index = 0xFE; // Nightshade special value

										pak.WriteByte((byte) spell.Value.Key.Level);
										if (spell.Value.Key.InstrumentRequirement == 0)
										{
											pak.WriteByte((byte) eSkillPage.Spells);
											pak.WriteByte(0);
											pak.WriteByte((byte) spec_index);
										}
										else
										{
											pak.WriteByte((byte) eSkillPage.Songs);
											pak.WriteByte(0);
											pak.WriteByte(0xFF);
										}
										pak.WriteByte(0);
										pak.WriteShort(spell.Value.Key.Icon);
										pak.WritePascalString(spell.Value.Key.Name);
									}
								}
							}
						}
					}

					if (pak.Length > 7)
					{
						pak.Position = 4;
						pak.WriteByte((byte) (maxSkills - firstSkills)); //number of entry
						pak.WriteByte(0x03); //subtype
						pak.WriteByte((byte) firstSkills);

						SendTCP(pak);
					}

					SendNonHybridSpellLines();
				}
			}

			finally
			{
				pak.Close();
			}
		}