public static LanguageDataObject GetLanguageDataObject(string language, string translationId, LanguageDataObject.eTranslationIdentifier translationIdentifier) { if (Util.IsEmpty(language) || Util.IsEmpty(translationId)) { return(null); } if (!m_translations.ContainsKey(language)) { return(null); } if (m_translations[language] == null) { lock (m_translations) m_translations.Remove(language); return(null); } if (!m_translations[language].ContainsKey(translationIdentifier)) { return(null); } if (m_translations[language][translationIdentifier] == null) { lock (m_translations) m_translations[language].Remove(translationIdentifier); return(null); } LanguageDataObject result = null; foreach (LanguageDataObject colObj in m_translations[language][translationIdentifier]) { if (colObj.TranslationIdentifier != translationIdentifier) { continue; } if (colObj.TranslationId != translationId) { continue; } if (colObj.Language != language) { continue; } result = colObj; break; } return(result); }
public static bool TryGetTranslation(out LanguageDataObject translation, GameClient client, ITranslatableObject obj) { if (client == null) { translation = null; return(false); } return(TryGetTranslation(out translation, (client.Account == null ? String.Empty : client.Account.Language), obj)); }
public static bool RegisterLanguageDataObject(LanguageDataObject obj) { if (obj != null) { lock (m_translations) { if (!m_translations.ContainsKey(obj.Language)) { IDictionary <LanguageDataObject.eTranslationIdentifier, IList <LanguageDataObject> > col = new Dictionary <LanguageDataObject.eTranslationIdentifier, IList <LanguageDataObject> >(); IList <LanguageDataObject> objs = new List <LanguageDataObject>(); objs.Add(obj); col.Add(obj.TranslationIdentifier, objs); m_translations.Add(obj.Language, col); return(true); } else if (m_translations[obj.Language] == null) { IDictionary <LanguageDataObject.eTranslationIdentifier, IList <LanguageDataObject> > col = new Dictionary <LanguageDataObject.eTranslationIdentifier, IList <LanguageDataObject> >(); IList <LanguageDataObject> objs = new List <LanguageDataObject>(); objs.Add(obj); col.Add(obj.TranslationIdentifier, objs); m_translations[obj.Language] = col; return(true); } else if (!m_translations[obj.Language].ContainsKey(obj.TranslationIdentifier)) { IDictionary <LanguageDataObject.eTranslationIdentifier, IList <LanguageDataObject> > col = new Dictionary <LanguageDataObject.eTranslationIdentifier, IList <LanguageDataObject> >(); IList <LanguageDataObject> objs = new List <LanguageDataObject>(); objs.Add(obj); m_translations[obj.Language].Add(obj.TranslationIdentifier, objs); return(true); } else if (m_translations[obj.Language][obj.TranslationIdentifier] == null) { IList <LanguageDataObject> objs = new List <LanguageDataObject>(); objs.Add(obj); m_translations[obj.Language][obj.TranslationIdentifier] = objs; } else if (!m_translations[obj.Language][obj.TranslationIdentifier].Contains(obj)) { lock (m_translations[obj.Language][obj.TranslationIdentifier]) { if (!m_translations[obj.Language][obj.TranslationIdentifier].Contains(obj)) { m_translations[obj.Language][obj.TranslationIdentifier].Add(obj); return(true); } } } } } return(false); // Object is 'NULL' or already in list. }
public static bool TryGetTranslation(out string translation, string language, string translationId, params object[] args) { translation = string.Empty; if (Util.IsEmpty(translationId)) { translation = TRANSLATION_ID_EMPTY; return(false); } if (Util.IsEmpty(language) || !m_translations.ContainsKey(language)) { language = DefaultLanguage; } LanguageDataObject result = GetLanguageDataObject(language, translationId, LanguageDataObject.eTranslationIdentifier.eSystem); if (result == null) { translation = GetTranslationErrorText(language, translationId); return(false); } else { if (!Util.IsEmpty(((DBLanguageSystem)result).Text)) { translation = ((DBLanguageSystem)result).Text; } else { translation = GetTranslationErrorText(language, translationId); return(false); } } if (args == null) { args = new object[0]; } try { if (args.Length > 0) { translation = string.Format(translation, args); } } catch { log.ErrorFormat("[Language-Manager] Parameter number incorrect: {0} for language {1}, Arg count = {2}, sentence = '{3}', args[0] = '{4}'", translationId, language, args.Length, translation, args.Length > 0 ? args[0] : "null"); } return(true); }
public static bool TryGetTranslation(out LanguageDataObject translation, string language, ITranslatableObject obj) { if (obj == null) { translation = null; return(false); } if (Util.IsEmpty(language) || language == DefaultLanguage /*Use the objects base data (e.g. NPC.Name)*/) { translation = null; return(false); } translation = GetLanguageDataObject(language, obj.TranslationId, obj.TranslationIdentifier); return(translation == null ? false : true); }
/// <summary> /// Called whenever a player enters the given area /// </summary> /// <param name="player"></param> public virtual void OnPlayerEnter(GamePlayer player) { if (m_displayMessage && Description != null && Description != "") { string description = Description; string screenDescription = description; LanguageDataObject translation = LanguageMgr.GetTranslation(player.Client.Account.Language, this); if (translation != null) { if (!Util.IsEmpty(((DBLanguageArea)translation).Description)) { description = ((DBLanguageArea)translation).Description; } if (!Util.IsEmpty(((DBLanguageArea)translation).ScreenDescription)) { screenDescription = ((DBLanguageArea)translation).ScreenDescription; } } player.Out.SendMessage(LanguageMgr.GetTranslation(player.Client.Account.Language, "AbstractArea.Entered", description), eChatType.CT_System, eChatLoc.CL_SystemWindow); //Changed by Apo 9. August 2010: Areas never send an screen description, but we will support it with an server property if (ServerProperties.Properties.DISPLAY_AREA_ENTER_SCREEN_DESC) { player.Out.SendMessage(screenDescription, eChatType.CT_ScreenCenterSmaller, eChatLoc.CL_SystemWindow); } } if (Sound != 0) { player.Out.SendRegionEnterSound(Sound); } player.Notify(AreaEvent.PlayerEnter, this, new AreaEventArgs(this, player)); }
/// <summary> /// Inits the language. /// </summary> /// <param name="_settingObject">Setting object.</param> private static void InitLanguage(LocalizationSetting.SettingObject _settingObject) { GameObject language = Resources.Load(_settingObject.GetPath()) as GameObject; languageObject = new LanguageDataObject(language, _settingObject); }
public static void UnregisterLanguageDataObject(LanguageDataObject obj) { lock (m_translations) { if (!m_translations.ContainsKey(obj.Language)) { return; } if (m_translations[obj.Language] == null) { lock (m_translations) m_translations.Remove(obj.Language); return; } if (!m_translations[obj.Language].ContainsKey(obj.TranslationIdentifier)) { if (m_translations[obj.Language].Count < 1) { lock (m_translations) m_translations.Remove(obj.Language); } return; } if (m_translations[obj.Language][obj.TranslationIdentifier] == null) { lock (m_translations) m_translations[obj.Language].Remove(obj.TranslationIdentifier); return; } if (!m_translations[obj.Language][obj.TranslationIdentifier].Contains(obj)) { if (m_translations[obj.Language][obj.TranslationIdentifier].Count < 1) { lock (m_translations) m_translations[obj.Language].Remove(obj.TranslationIdentifier); } return; } lock (m_translations[obj.Language][obj.TranslationIdentifier]) m_translations[obj.Language][obj.TranslationIdentifier].Remove(obj); if (m_translations[obj.Language][obj.TranslationIdentifier].Count < 1) { lock (m_translations) m_translations[obj.Language].Remove(obj.TranslationIdentifier); return; } if (m_translations[obj.Language].Count < 1) { lock (m_translations) m_translations.Remove(obj.Language); } } }
// Dunnerholl 2009-09-10 i do not like the way this is done public override void SendCharacterOverview(eRealm realm) { int firstAccountSlot; switch (realm) { case eRealm.Albion: firstAccountSlot = 100; break; case eRealm.Midgard: firstAccountSlot = 200; break; case eRealm.Hibernia: firstAccountSlot = 300; break; default: throw new Exception("CharacterOverview requested for unknown realm " + realm); } using (GSTCPPacketOut pak = new GSTCPPacketOut(GetPacketCode(eServerPackets.CharacterOverview))) { pak.FillString(m_gameClient.Account.Name, 24); IList <InventoryItem> items; DOLCharacters[] characters = m_gameClient.Account.Characters; if (characters == null) { pak.Fill(0x0, 1880); } else { for (int i = firstAccountSlot; i < firstAccountSlot + 10; i++) { bool written = false; for (int j = 0; j < characters.Length && !written; j++) { if (characters[j].AccountSlot == i) { pak.FillString(characters[j].Name, 24); items = GameServer.Database.SelectObjects <InventoryItem>("OwnerID = '" + GameServer.Database.Escape(characters[j].ObjectId) + "' AND SlotPosition >='10' AND SlotPosition <= '37'"); byte ExtensionTorso = 0; byte ExtensionGloves = 0; byte ExtensionBoots = 0; foreach (InventoryItem item in items) { switch (item.SlotPosition) { case 22: ExtensionGloves = item.Extension; break; case 23: ExtensionBoots = item.Extension; break; case 25: ExtensionTorso = item.Extension; break; default: break; } } pak.WriteByte(0x01); pak.WriteByte((byte)characters[j].EyeSize); pak.WriteByte((byte)characters[j].LipSize); pak.WriteByte((byte)characters[j].EyeColor); pak.WriteByte((byte)characters[j].HairColor); pak.WriteByte((byte)characters[j].FaceType); pak.WriteByte((byte)characters[j].HairStyle); pak.WriteByte((byte)((ExtensionBoots << 4) | ExtensionGloves)); pak.WriteByte((byte)((ExtensionTorso << 4) | (characters[j].IsCloakHoodUp ? 0x1 : 0x0))); pak.WriteByte((byte)characters[j].CustomisationStep); //1 = auto generate config, 2= config ended by player, 3= enable config to player pak.WriteByte((byte)characters[j].MoodType); pak.Fill(0x0, 13); //0 String Region reg = WorldMgr.GetRegion((ushort)characters[j].Region); Zone zon = null; if (reg != null) { zon = reg.GetZone(characters[j].Xpos, characters[j].Ypos); } if (zon != null) { IList areas = zon.GetAreasOfSpot(characters[j].Xpos, characters[j].Ypos, characters[j].Zpos); string description = ""; foreach (AbstractArea area in areas) { if (!area.DisplayMessage) { continue; } description = area.Description; LanguageDataObject translation = LanguageMgr.GetTranslation(m_gameClient, area); if (translation != null) { if (!Util.IsEmpty(((DBLanguageArea)translation).ScreenDescription)) // Thats correct! { description = ((DBLanguageArea)translation).ScreenDescription; } } break; } if (description == "") { description = zon.Description; LanguageDataObject translation = LanguageMgr.GetTranslation(m_gameClient, zon); if (translation != null) { if (!Util.IsEmpty(((DBLanguageZone)translation).ScreenDescription)) // Thats correct! { description = ((DBLanguageZone)translation).ScreenDescription; } } } pak.FillString(description, 24); } else { pak.Fill(0x0, 24); //No known location } if (characters[j].Class == 0) { pak.FillString("", 24); //Class name } else { pak.FillString(((eCharacterClass)characters[j].Class).ToString(), 24); //Class name } //pak.FillString(GamePlayer.RACENAMES[characters[j].Race], 24); pak.FillString(GamePlayer.RACENAMES(m_gameClient, characters[j].Race, characters[j].Gender), 24); pak.WriteByte((byte)characters[j].Level); pak.WriteByte((byte)characters[j].Class); pak.WriteByte((byte)characters[j].Realm); pak.WriteByte((byte)((((characters[j].Race & 0x10) << 2) + (characters[j].Race & 0x0F)) | (characters[j].Gender << 4))); // race max value can be 0x1F pak.WriteShortLowEndian((ushort)characters[j].CurrentModel); pak.WriteByte((byte)characters[j].Region); if (reg == null || (int)m_gameClient.ClientType > reg.Expansion) { pak.WriteByte(0x00); } else { pak.WriteByte((byte)(reg.Expansion + 1)); //0x04-Cata zone, 0x05 - DR zone } pak.WriteInt(0x0); // Internal database ID pak.WriteByte((byte)characters[j].Strength); pak.WriteByte((byte)characters[j].Dexterity); pak.WriteByte((byte)characters[j].Constitution); pak.WriteByte((byte)characters[j].Quickness); pak.WriteByte((byte)characters[j].Intelligence); pak.WriteByte((byte)characters[j].Piety); pak.WriteByte((byte)characters[j].Empathy); pak.WriteByte((byte)characters[j].Charisma); int found = 0; //16 bytes: armor model for (int k = 0x15; k < 0x1D; k++) { found = 0; foreach (InventoryItem item in items) { if (item.SlotPosition == k && found == 0) { pak.WriteShortLowEndian((ushort)item.Model); found = 1; } } if (found == 0) { pak.WriteShort(0x00); } } //16 bytes: armor color for (int k = 0x15; k < 0x1D; k++) { int l; if (k == 0x15 + 3) { //shield emblem l = (int)eInventorySlot.LeftHandWeapon; } else { l = k; } found = 0; foreach (InventoryItem item in items) { if (item.SlotPosition == l && found == 0) { if (item.Emblem != 0) { pak.WriteShortLowEndian((ushort)item.Emblem); } else { pak.WriteShortLowEndian((ushort)item.Color); } found = 1; } } if (found == 0) { pak.WriteShort(0x00); } } //8 bytes: weapon model for (int k = 0x0A; k < 0x0E; k++) { found = 0; foreach (InventoryItem item in items) { if (item.SlotPosition == k && found == 0) { pak.WriteShortLowEndian((ushort)item.Model); found = 1; } } if (found == 0) { pak.WriteShort(0x00); } } if (characters[j].ActiveWeaponSlot == (byte)GameLiving.eActiveWeaponSlot.TwoHanded) { pak.WriteByte(0x02); pak.WriteByte(0x02); } else if (characters[j].ActiveWeaponSlot == (byte)GameLiving.eActiveWeaponSlot.Distance) { pak.WriteByte(0x03); pak.WriteByte(0x03); } else { byte righthand = 0xFF; byte lefthand = 0xFF; foreach (InventoryItem item in items) { if (item.SlotPosition == (int)eInventorySlot.RightHandWeapon) { righthand = 0x00; } if (item.SlotPosition == (int)eInventorySlot.LeftHandWeapon) { lefthand = 0x01; } } if (righthand == lefthand) { if (characters[j].ActiveWeaponSlot == (byte)GameLiving.eActiveWeaponSlot.TwoHanded) { righthand = lefthand = 0x02; } else if (characters[j].ActiveWeaponSlot == (byte)GameLiving.eActiveWeaponSlot.Distance) { righthand = lefthand = 0x03; } } pak.WriteByte(righthand); pak.WriteByte(lefthand); } if (reg == null || reg.Expansion != 1) { pak.WriteByte(0x00); } else { pak.WriteByte(0x01); //0x01=char in ShroudedIsles zone, classic client can't "play" } pak.WriteByte((byte)characters[j].Constitution); pak.Fill(0x0, 4); //new trailing bytes in 1.99 written = true; } } if (!written) { pak.Fill(0x0, 188); } } } pak.Fill(0x0, 90); SendTCP(pak); } }
public override void SendSiegeWeaponInterface(GameSiegeWeapon siegeWeapon, int time) { using (GSTCPPacketOut pak = new GSTCPPacketOut(GetPacketCode(eServerPackets.SiegeWeaponInterface))) { ushort flag = (ushort)((siegeWeapon.EnableToMove ? 1 : 0) | siegeWeapon.AmmoType << 8); pak.WriteShort(flag); //byte Ammo, byte SiegeMoving(1/0) pak.WriteByte(0); pak.WriteByte(0); // Close interface(1/0) pak.WriteByte((byte)(time)); //time in 100ms pak.WriteByte((byte)siegeWeapon.Ammo.Count); // external ammo count pak.WriteByte((byte)siegeWeapon.SiegeWeaponTimer.CurrentAction); pak.WriteByte((byte)siegeWeapon.AmmoSlot); pak.WriteShort(siegeWeapon.Effect); pak.WriteShort(0); // SiegeHelperTimer ? pak.WriteShort(0); // SiegeTimer ? pak.WriteShort((ushort)siegeWeapon.ObjectID); string name = siegeWeapon.Name; LanguageDataObject translation = LanguageMgr.GetTranslation(m_gameClient, siegeWeapon); if (translation != null) { if (!Util.IsEmpty(((DBLanguageNPC)translation).Name)) { name = ((DBLanguageNPC)translation).Name; } } pak.WritePascalString(name + " (" + siegeWeapon.CurrentState.ToString() + ")"); foreach (InventoryItem item in siegeWeapon.Ammo) { pak.WriteByte((byte)item.SlotPosition); if (item == null) { pak.Fill(0x00, 18); continue; } pak.WriteByte((byte)item.Level); pak.WriteByte((byte)item.DPS_AF); pak.WriteByte((byte)item.SPD_ABS); pak.WriteByte((byte)(item.Hand * 64)); pak.WriteByte((byte)((item.Type_Damage * 64) + item.Object_Type)); pak.WriteShort((ushort)item.Weight); pak.WriteByte(item.ConditionPercent); // % of con pak.WriteByte(item.DurabilityPercent); // % of dur pak.WriteByte((byte)item.Quality); // % of qua pak.WriteByte((byte)item.Bonus); // % bonus pak.WriteShort((ushort)item.Model); if (item.Emblem != 0) { pak.WriteShort((ushort)item.Emblem); } else { pak.WriteShort((ushort)item.Color); } pak.WriteShort((ushort)item.Effect); if (item.Count > 1) { pak.WritePascalString(item.Count + " " + item.Name); } else { pak.WritePascalString(item.Name); } } SendTCP(pak); } }
public override void SendObjectCreate(GameObject obj) { if (obj == null || m_gameClient.Player == null) { return; } if (obj.IsVisibleTo(m_gameClient.Player) == false) { return; } using (GSTCPPacketOut pak = new GSTCPPacketOut(GetPacketCode(eServerPackets.ObjectCreate))) { pak.WriteShort((ushort)obj.ObjectID); if (obj is GameStaticItem) { pak.WriteShort((ushort)(obj as GameStaticItem).Emblem); } else { pak.WriteShort(0); } pak.WriteShort(obj.Heading); pak.WriteShort((ushort)obj.Z); pak.WriteInt((uint)obj.X); pak.WriteInt((uint)obj.Y); int flag = ((byte)obj.Realm & 3) << 4; ushort model = obj.Model; if (obj.IsUnderwater) { if (obj is GameNPC) { model |= 0x8000; } else { flag |= 0x01; // Underwater } } pak.WriteShort(model); if (obj is GameKeepBanner) { flag |= 0x08; } if (obj is GameStaticItemTimed && m_gameClient.Player != null && ((GameStaticItemTimed)obj).IsOwner(m_gameClient.Player)) { flag |= 0x04; } pak.WriteShort((ushort)flag); pak.WriteInt(0x0); //TODO: unknown, new in 1.71 string name = obj.Name; LanguageDataObject translation = null; if (obj is GameStaticItem) { translation = LanguageMgr.GetTranslation(m_gameClient, (GameStaticItem)obj); if (translation != null) { if (obj is WorldInventoryItem) { //if (!Util.IsEmpty(((DBLanguageItem)translation).Name)) // name = ((DBLanguageItem)translation).Name; } else { if (!Util.IsEmpty(((DBLanguageGameObject)translation).Name)) { name = ((DBLanguageGameObject)translation).Name; } } } } pak.WritePascalString(name); if (obj is IDoor) { pak.WriteByte(4); pak.WriteInt((uint)(obj as IDoor).DoorID); } else { pak.WriteByte(0x00); } SendTCP(pak); } // Update Object Cache m_gameClient.GameObjectUpdateArray[new Tuple <ushort, ushort>(obj.CurrentRegionID, (ushort)obj.ObjectID)] = GameTimer.GetTickCount(); }
public override void SendNPCCreate(GameNPC npc) { if (m_gameClient.Player == null || npc.IsVisibleTo(m_gameClient.Player) == false) { return; } //Added by Suncheck - Mines are not shown to enemy players if (npc is GameMine) { if (GameServer.ServerRules.IsAllowedToAttack((npc as GameMine).Owner, m_gameClient.Player, true)) { return; } } if (npc is GameMovingObject) { SendMovingObjectCreate(npc as GameMovingObject); return; } using (GSTCPPacketOut pak = new GSTCPPacketOut(GetPacketCode(eServerPackets.NPCCreate))) { int speed = 0; ushort speedZ = 0; if (npc == null) { return; } if (!npc.IsAtTargetPosition) { speed = npc.CurrentSpeed; speedZ = (ushort)npc.TickSpeedZ; } pak.WriteShort((ushort)npc.ObjectID); pak.WriteShort((ushort)(speed)); pak.WriteShort(npc.Heading); pak.WriteShort((ushort)npc.Z); pak.WriteInt((uint)npc.X); pak.WriteInt((uint)npc.Y); pak.WriteShort(speedZ); pak.WriteShort(npc.Model); pak.WriteByte(npc.Size); byte level = npc.GetDisplayLevel(m_gameClient.Player); if ((npc.Flags & GameNPC.eFlags.STATUE) != 0) { level |= 0x80; } pak.WriteByte(level); byte flags = (byte)(GameServer.ServerRules.GetLivingRealm(m_gameClient.Player, npc) << 6); if ((npc.Flags & GameNPC.eFlags.GHOST) != 0) { flags |= 0x01; } if (npc.Inventory != null) { flags |= 0x02; //If mob has equipment, then only show it after the client gets the 0xBD packet } if ((npc.Flags & GameNPC.eFlags.PEACE) != 0) { flags |= 0x10; } if ((npc.Flags & GameNPC.eFlags.FLYING) != 0) { flags |= 0x20; } if ((npc.Flags & GameNPC.eFlags.TORCH) != 0) { flags |= 0x04; } pak.WriteByte(flags); pak.WriteByte(0x20); //TODO this is the default maxstick distance string add = ""; byte flags2 = 0x00; IControlledBrain brain = npc.Brain as IControlledBrain; if (m_gameClient.Version >= GameClient.eClientVersion.Version187) { if (brain != null) { flags2 |= 0x80; // have Owner } } if ((npc.Flags & GameNPC.eFlags.CANTTARGET) != 0) { if (m_gameClient.Account.PrivLevel > 1) { add += "-DOR"; // indicates DOR flag for GMs } else { flags2 |= 0x01; } } if ((npc.Flags & GameNPC.eFlags.DONTSHOWNAME) != 0) { if (m_gameClient.Account.PrivLevel > 1) { add += "-NON"; // indicates NON flag for GMs } else { flags2 |= 0x02; } } if ((npc.Flags & GameNPC.eFlags.STEALTH) > 0) { flags2 |= 0x04; } eQuestIndicator questIndicator = npc.GetQuestIndicator(m_gameClient.Player); if (questIndicator == eQuestIndicator.Available) { flags2 |= 0x08; //hex 8 - quest available } if (questIndicator == eQuestIndicator.Finish) { flags2 |= 0x10; //hex 16 - quest finish } //flags2 |= 0x20;//hex 32 - water mob? //flags2 |= 0x40;//hex 64 - unknown //flags2 |= 0x80;//hex 128 - has owner pak.WriteByte(flags2); // flags 2 byte flags3 = 0x00; if (questIndicator == eQuestIndicator.Lesson) { flags3 |= 0x01; } if (questIndicator == eQuestIndicator.Lore) { flags3 |= 0x02; } pak.WriteByte(flags3); // new in 1.71 (region instance ID from StoC_0x20) OR flags 3? pak.WriteShort(0x00); // new in 1.71 unknown string name = npc.Name; string guildName = npc.GuildName; LanguageDataObject translation = LanguageMgr.GetTranslation(m_gameClient, npc); if (translation != null) { if (!Util.IsEmpty(((DBLanguageNPC)translation).Name)) { name = ((DBLanguageNPC)translation).Name; } if (!Util.IsEmpty(((DBLanguageNPC)translation).GuildName)) { guildName = ((DBLanguageNPC)translation).GuildName; } } if (name.Length + add.Length + 2 > 47) // clients crash with too long names { name = name.Substring(0, 47 - add.Length - 2); } if (add.Length > 0) { name = string.Format("[{0}]{1}", name, add); } pak.WritePascalString(name); if (guildName.Length > 47) { pak.WritePascalString(guildName.Substring(0, 47)); } else { pak.WritePascalString(guildName); } pak.WriteByte(0x00); SendTCP(pak); } // Update Cache m_gameClient.GameObjectUpdateArray[new Tuple <ushort, ushort>(npc.CurrentRegionID, (ushort)npc.ObjectID)] = 0; }
public override void SendCharacterOverview(eRealm realm) { if (realm < eRealm.Albion || realm > eRealm.Hibernia) { throw new Exception("CharacterOverview requested for unknown realm " + realm); } int firstSlot = (byte)realm * 100; using (GSTCPPacketOut pak = new GSTCPPacketOut(GetPacketCode(eServerPackets.CharacterOverview))) { pak.FillString(m_gameClient.Account.Name, 28); //extra 4 in 1.104 if (m_gameClient.Account.Characters == null) { pak.Fill(0x0, 1880); } else { Dictionary <int, DOLCharacters> charsBySlot = new Dictionary <int, DOLCharacters>(); string itemQuery = "("; foreach (DOLCharacters c in m_gameClient.Account.Characters) { try { charsBySlot.Add(c.AccountSlot, c); itemQuery += "OwnerID = '" + c.ObjectId + "' OR "; } catch (Exception ex) { log.Error("SendCharacterOverview - Duplicate char in slot? Slot: " + c.AccountSlot + ", Account: " + c.AccountName, ex); } } itemQuery = itemQuery.Substring(0, itemQuery.Length - 4); //remove last OR itemQuery += ") AND SlotPosition >= " + ((int)eInventorySlot.MinEquipable) + " AND SlotPosition <= " + ((int)eInventorySlot.MaxEquipable); var itemsByOwnerID = new Dictionary <string, Dictionary <eInventorySlot, InventoryItem> >(); var allItems = (InventoryItem[])GameServer.Database.SelectObjects <InventoryItem>(itemQuery); foreach (InventoryItem item in allItems) { try { if (!itemsByOwnerID.ContainsKey(item.OwnerID)) { itemsByOwnerID.Add(item.OwnerID, new Dictionary <eInventorySlot, InventoryItem>()); } itemsByOwnerID[item.OwnerID].Add((eInventorySlot)item.SlotPosition, item); } catch (Exception ex) { log.Error("SendCharacterOverview - Duplicate item on character? OwnerID: " + item.OwnerID + ", SlotPosition: " + item.SlotPosition + ", Account: " + m_gameClient.Account.Name, ex); } } for (int i = firstSlot; i < (firstSlot + 10); i++) { DOLCharacters c = null; if (!charsBySlot.TryGetValue(i, out c)) { pak.Fill(0x0, 188); } else { Dictionary <eInventorySlot, InventoryItem> charItems = null; if (!itemsByOwnerID.TryGetValue(c.ObjectId, out charItems)) { charItems = new Dictionary <eInventorySlot, InventoryItem>(); } byte extensionTorso = 0; byte extensionGloves = 0; byte extensionBoots = 0; InventoryItem item = null; if (charItems.TryGetValue(eInventorySlot.TorsoArmor, out item)) { extensionTorso = item.Extension; } if (charItems.TryGetValue(eInventorySlot.HandsArmor, out item)) { extensionGloves = item.Extension; } if (charItems.TryGetValue(eInventorySlot.FeetArmor, out item)) { extensionBoots = item.Extension; } pak.FillString(c.Name, 24); pak.WriteByte(0x01); pak.WriteByte((byte)c.EyeSize); pak.WriteByte((byte)c.LipSize); pak.WriteByte((byte)c.EyeColor); pak.WriteByte((byte)c.HairColor); pak.WriteByte((byte)c.FaceType); pak.WriteByte((byte)c.HairStyle); pak.WriteByte((byte)((extensionBoots << 4) | extensionGloves)); pak.WriteByte((byte)((extensionTorso << 4) | (c.IsCloakHoodUp ? 0x1 : 0x0))); pak.WriteByte((byte)c.CustomisationStep); //1 = auto generate config, 2= config ended by player, 3= enable config to player pak.WriteByte((byte)c.MoodType); pak.Fill(0x0, 13); //0 String string locationDescription = ""; Region region = WorldMgr.GetRegion((ushort)c.Region); if (region != null) { Zone zone = null; if ((zone = region.GetZone(c.Xpos, c.Ypos)) != null) { IList areas = zone.GetAreasOfSpot(c.Xpos, c.Ypos, c.Zpos); foreach (AbstractArea area in areas) { if (!area.DisplayMessage) { continue; } locationDescription = area.Description; LanguageDataObject translation = LanguageMgr.GetTranslation(m_gameClient, area); if (translation != null) { if (!Util.IsEmpty(((DBLanguageArea)translation).ScreenDescription)) // Thats correct! { locationDescription = ((DBLanguageArea)translation).ScreenDescription; } } break; } if (locationDescription == "") { locationDescription = zone.Description; LanguageDataObject translation = LanguageMgr.GetTranslation(m_gameClient, zone); if (translation != null) { if (!Util.IsEmpty(((DBLanguageZone)translation).ScreenDescription)) // Thats correct! { locationDescription = ((DBLanguageZone)translation).ScreenDescription; } } } } } pak.FillString(locationDescription, 24); string classname = ""; if (c.Class != 0) { classname = ((eCharacterClass)c.Class).ToString(); } pak.FillString(classname, 24); string racename = GamePlayer.RACENAMES(m_gameClient, c.Race, c.Gender); pak.FillString(racename, 24); pak.WriteByte((byte)c.Level); pak.WriteByte((byte)c.Class); pak.WriteByte((byte)c.Realm); pak.WriteByte((byte)((((c.Race & 0x10) << 2) + (c.Race & 0x0F)) | (c.Gender << 4))); // race max value can be 0x1F pak.WriteShortLowEndian((ushort)c.CurrentModel); pak.WriteByte((byte)c.Region); if (region == null || (int)m_gameClient.ClientType > region.Expansion) { pak.WriteByte(0x00); } else { pak.WriteByte((byte)(region.Expansion + 1)); //0x04-Cata zone, 0x05 - DR zone } pak.WriteInt(0x0); // Internal database ID pak.WriteByte((byte)c.Strength); pak.WriteByte((byte)c.Dexterity); pak.WriteByte((byte)c.Constitution); pak.WriteByte((byte)c.Quickness); pak.WriteByte((byte)c.Intelligence); pak.WriteByte((byte)c.Piety); pak.WriteByte((byte)c.Empathy); pak.WriteByte((byte)c.Charisma); InventoryItem rightHandWeapon = null; charItems.TryGetValue(eInventorySlot.RightHandWeapon, out rightHandWeapon); InventoryItem leftHandWeapon = null; charItems.TryGetValue(eInventorySlot.LeftHandWeapon, out leftHandWeapon); InventoryItem twoHandWeapon = null; charItems.TryGetValue(eInventorySlot.TwoHandWeapon, out twoHandWeapon); InventoryItem distanceWeapon = null; charItems.TryGetValue(eInventorySlot.DistanceWeapon, out distanceWeapon); InventoryItem helmet = null; charItems.TryGetValue(eInventorySlot.HeadArmor, out helmet); InventoryItem gloves = null; charItems.TryGetValue(eInventorySlot.HandsArmor, out gloves); InventoryItem boots = null; charItems.TryGetValue(eInventorySlot.FeetArmor, out boots); InventoryItem torso = null; charItems.TryGetValue(eInventorySlot.TorsoArmor, out torso); InventoryItem cloak = null; charItems.TryGetValue(eInventorySlot.Cloak, out cloak); InventoryItem legs = null; charItems.TryGetValue(eInventorySlot.LegsArmor, out legs); InventoryItem arms = null; charItems.TryGetValue(eInventorySlot.ArmsArmor, out arms); pak.WriteShortLowEndian((ushort)(helmet != null ? helmet.Model : 0)); pak.WriteShortLowEndian((ushort)(gloves != null ? gloves.Model : 0)); pak.WriteShortLowEndian((ushort)(boots != null ? boots.Model : 0)); ushort rightHandColor = 0; if (rightHandWeapon != null) { rightHandColor = (ushort)(rightHandWeapon.Emblem != 0 ? rightHandWeapon.Emblem : rightHandWeapon.Color); } pak.WriteShortLowEndian(rightHandColor); pak.WriteShortLowEndian((ushort)(torso != null ? torso.Model : 0)); pak.WriteShortLowEndian((ushort)(cloak != null ? cloak.Model : 0)); pak.WriteShortLowEndian((ushort)(legs != null ? legs.Model : 0)); pak.WriteShortLowEndian((ushort)(arms != null ? arms.Model : 0)); ushort helmetColor = 0; if (helmet != null) { helmetColor = (ushort)(helmet.Emblem != 0 ? helmet.Emblem : helmet.Color); } pak.WriteShortLowEndian(helmetColor); ushort glovesColor = 0; if (gloves != null) { glovesColor = (ushort)(gloves.Emblem != 0 ? gloves.Emblem : gloves.Color); } pak.WriteShortLowEndian(glovesColor); ushort bootsColor = 0; if (boots != null) { bootsColor = (ushort)(boots.Emblem != 0 ? boots.Emblem : boots.Color); } pak.WriteShortLowEndian(bootsColor); ushort leftHandWeaponColor = 0; if (leftHandWeapon != null) { leftHandWeaponColor = (ushort)(leftHandWeapon.Emblem != 0 ? leftHandWeapon.Emblem : leftHandWeapon.Color); } pak.WriteShortLowEndian(leftHandWeaponColor); ushort torsoColor = 0; if (torso != null) { torsoColor = (ushort)(torso.Emblem != 0 ? torso.Emblem : torso.Color); } pak.WriteShortLowEndian(torsoColor); ushort cloakColor = 0; if (cloak != null) { cloakColor = (ushort)(cloak.Emblem != 0 ? cloak.Emblem : cloak.Color); } pak.WriteShortLowEndian(cloakColor); ushort legsColor = 0; if (legs != null) { legsColor = (ushort)(legs.Emblem != 0 ? legs.Emblem : legs.Color); } pak.WriteShortLowEndian(legsColor); ushort armsColor = 0; if (arms != null) { armsColor = (ushort)(arms.Emblem != 0 ? arms.Emblem : arms.Color); } pak.WriteShortLowEndian(armsColor); //weapon models pak.WriteShortLowEndian((ushort)(rightHandWeapon != null ? rightHandWeapon.Model : 0)); pak.WriteShortLowEndian((ushort)(leftHandWeapon != null ? leftHandWeapon.Model : 0)); pak.WriteShortLowEndian((ushort)(twoHandWeapon != null ? twoHandWeapon.Model : 0)); pak.WriteShortLowEndian((ushort)(distanceWeapon != null ? distanceWeapon.Model : 0)); if (c.ActiveWeaponSlot == (byte)DOL.GS.GameLiving.eActiveWeaponSlot.TwoHanded) { pak.WriteByte(0x02); pak.WriteByte(0x02); } else if (c.ActiveWeaponSlot == (byte)DOL.GS.GameLiving.eActiveWeaponSlot.Distance) { pak.WriteByte(0x03); pak.WriteByte(0x03); } else { byte righthand = 0xFF; byte lefthand = 0xFF; if (rightHandWeapon != null) { righthand = 0x00; } if (leftHandWeapon != null) { lefthand = 0x01; } pak.WriteByte(righthand); pak.WriteByte(lefthand); } if (region == null || region.Expansion != 1) { pak.WriteByte(0x00); } else { pak.WriteByte(0x01); //0x01=char in SI zone, classic client can't "play" } pak.WriteByte((byte)c.Constitution); pak.Fill(0x00, 4); //new trailing bytes in 1.99 } } } pak.Fill(0x0, 90); SendTCP(pak); } }
public void OnCommand(GameClient client, string[] args) { if (IsSpammingCommand(client.Player, "translate")) { return; } if (args.Length < 2) { DisplaySyntax(client); return; } switch (args[1].ToLower()) { case "add": { if (client.Account.PrivLevel != (uint)ePrivLevel.Player) { if (args.Length < 5) { DisplayMessage(client, "[Language-Manager] Usage: '/translate add [Language] [TranslationId] [Text]'"); return; } LanguageDataObject translation = LanguageMgr.GetLanguageDataObject(args[2].ToUpper(), args[3], LanguageDataObject.eTranslationIdentifier.eSystem); if (translation != null) { DisplayMessage(client, "[Language-Manager] This translation id is already in use by the given language! ( Language <" + args[2].ToUpper() + "> - TranslationId <" + args[3] + "> )"); return; } translation = new DBLanguageSystem(); ((DBLanguageSystem)translation).TranslationId = args[3]; ((DBLanguageSystem)translation).Text = args[4]; ((DBLanguageSystem)translation).Language = args[2]; GameServer.Database.AddObject(translation); LanguageMgr.RegisterLanguageDataObject(translation); DisplayMessage(client, "[Language-Manager] Translation successfully added! (Language <" + args[2].ToUpper() + "> - TranslationId <" + args[3] + "> )"); return; } return; } case "debug": { bool debug = client.Player.TempProperties.getProperty("LANGUAGEMGR-DEBUG", false); debug = !debug; client.Player.TempProperties.setProperty("LANGUAGEMGR-DEBUG", debug); DisplayMessage(client, "[Language-Manager] Debug mode: " + (debug ? "ON" : "OFF")); return; } case "memadd": { // This sub command adds a new language object to your temp properties which will "pre save" the given translation id // and language. Use this sub command if the translation id or text of your new translation requires more room // as the DAoC chat allows you to use in one line. Use the memsave sub command to add a text to this language object // and to save it into the database - or use "memclear" to remove the language object from your temp properties. if (args.Length < 4) { DisplayMessage(client, "[Language-Manager] Usage: '/translate memadd [Language] [TranslationId]'"); } else { LanguageDataObject lngObj = (LanguageDataObject)client.Player.TempProperties.getProperty <object>(LANGUAGEMGR_MEM_LNG_OBJ, null); if (lngObj != null) { DisplayMessage(client, "[Language-Manager] Can't add language object, there is already another one!"); } else { lngObj = LanguageMgr.GetLanguageDataObject(args[2].ToUpper(), args[3], LanguageDataObject.eTranslationIdentifier.eSystem); if (lngObj != null) { DisplayMessage(client, "[Language-Manager] The combination of the given TranslationId <" + args[3] + "> and Language <" + args[2].ToUpper() + "> is already in use!"); } else { lngObj = new DBLanguageSystem(); ((DBLanguageSystem)lngObj).TranslationId = args[3]; ((DBLanguageSystem)lngObj).Language = args[2]; client.Player.TempProperties.setProperty(LANGUAGEMGR_MEM_LNG_OBJ, lngObj); DisplayMessage(client, "[Language-Manager] Language object successfully added to your temporary properties! ( Language <" + args[2].ToUpper() + "> TranslationId <" + args[3] + "> )"); } } } return; } case "memclear": { // Removes the language object from your temp properties you've previously added with the "memadd" sub command. LanguageDataObject lngObj = (LanguageDataObject)client.Player.TempProperties.getProperty <object>(LANGUAGEMGR_MEM_LNG_OBJ, null); if (lngObj == null) { DisplayMessage(client, "[Language-Manager] No language object found."); } else { client.Player.TempProperties.removeProperty(LANGUAGEMGR_MEM_LNG_OBJ); DisplayMessage(client, "[Language-Manager] Language object successfully removed."); } return; } case "memsave": { // See "memadd" sub command for a description. if (args.Length < 3) { DisplayMessage(client, "[Language-Manager] Usage: '/translate memsave [Text]'"); } else { LanguageDataObject lngObj = (LanguageDataObject)client.Player.TempProperties.getProperty <object>(LANGUAGEMGR_MEM_LNG_OBJ, null); if (lngObj == null) { DisplayMessage(client, "[Language-Manager] No language object found."); } else { if (args.Length > 3) { ((DBLanguageSystem)lngObj).Text = string.Join(" ", args, 2, args.Length - 2); } else { ((DBLanguageSystem)lngObj).Text = args[2]; } if (!LanguageMgr.RegisterLanguageDataObject(lngObj)) { DisplayMessage(client, "[Language-Manager] Can't register language object in LanguageMgr, there is already another one!"); } else { GameServer.Database.AddObject(lngObj); client.Player.TempProperties.removeProperty(LANGUAGEMGR_MEM_LNG_OBJ); DisplayMessage(client, "[Language-Manager] Translation successfully added into the database and registered in LanguageMgr."); } } } return; } case "memshow": { LanguageDataObject lngObj = (LanguageDataObject)client.Player.TempProperties.getProperty <object>(LANGUAGEMGR_MEM_LNG_OBJ, null); if (lngObj == null) { DisplayMessage(client, "[Language-Manager] No language object found."); } else { DisplayMessage(client, "[Language-Manager] Language object info: Language <" + lngObj.Language + "> TranslationId <" + lngObj.TranslationId + ">"); } return; } case "refresh": { if (args.Length < 5) { DisplayMessage(client, "[Language-Manager] Usage: '/translate refresh [Language] [TranslationId] [Text]'"); } else { LanguageDataObject lngObj = LanguageMgr.GetLanguageDataObject(args[2].ToUpper(), args[3], LanguageDataObject.eTranslationIdentifier.eSystem); if (lngObj == null) { DisplayMessage(client, "[Language-Manager] Can't find TranslationId <" + args[3] + "> (Language <" + args[2].ToUpper() + "> !"); } else { ((DBLanguageSystem)lngObj).Text = args[3]; GameServer.Database.SaveObject(lngObj); DisplayMessage(client, "[Language-Manager] TranslationId <" + args[3] + "> (Language: " + args[2].ToUpper() + " ) successfully updated in database!"); } } return; } case "select": { if (args.Length < 4) { DisplayMessage(client, "[Language-Manager] Usage: '/translate select [Language] [TranslationId]'"); } else { LanguageDataObject lngObj = (LanguageDataObject)client.Player.TempProperties.getProperty <object>(LANGUAGEMGR_SEL_LNG_OBJ, null); if (lngObj != null) { DisplayMessage(client, "[Language-Manager] You already have selected a language object! ( Language <" + ((DBLanguageSystem)lngObj).Language + "> - TranslationId <" + ((DBLanguageSystem)lngObj).TranslationId + "> )"); } else { lngObj = LanguageMgr.GetLanguageDataObject(args[2].ToUpper(), args[3], LanguageDataObject.eTranslationIdentifier.eSystem); if (lngObj == null) { DisplayMessage(client, "[Language-Manager] Can't find language object. ( Language <" + args[2].ToUpper() + "> - TranslationId <" + args[3] + "> )"); } else { client.Player.TempProperties.setProperty(LANGUAGEMGR_SEL_LNG_OBJ, lngObj); DisplayMessage(client, "[Language-Manager] Language object found and added to your temporary properties! ( Language <" + args[2].ToUpper() + "> - TranslationId <" + args[3] + "> )"); } } } return; } case "selectclear": { // Removes the language object from your temp properties you've previously selected with the "select" sub command. LanguageDataObject lngObj = (LanguageDataObject)client.Player.TempProperties.getProperty <object>(LANGUAGEMGR_SEL_LNG_OBJ, null); if (lngObj == null) { DisplayMessage(client, "[Language-Manager] No language object selected!"); } else { client.Player.TempProperties.removeProperty(LANGUAGEMGR_SEL_LNG_OBJ); DisplayMessage(client, "[Language-Manager] Language object successfully removed from your temporary properties." + "( Language <" + ((DBLanguageSystem)lngObj).Language + "> - TranslationId <" + ((DBLanguageSystem)lngObj).TranslationId + "> )"); } return; } case "selectsave": { if (args.Length < 3) { DisplayMessage(client, "[Language-Manager] Usage: '/translate selectsave [Text]'"); } else { LanguageDataObject lngObj = (LanguageDataObject)client.Player.TempProperties.getProperty <object>(LANGUAGEMGR_SEL_LNG_OBJ, null); if (lngObj == null) { DisplayMessage(client, "[Language-Manager] No language object selected!"); } else { if (args.Length > 3) { ((DBLanguageSystem)lngObj).Text = string.Join(" ", args, 2, args.Length - 2); } else { ((DBLanguageSystem)lngObj).Text = args[2]; } GameServer.Database.SaveObject(lngObj); client.Player.TempProperties.removeProperty(LANGUAGEMGR_SEL_LNG_OBJ); DisplayMessage(client, "[Language-Manager] Language object successfully changed and saved in database." + "( Language <" + ((DBLanguageSystem)lngObj).Language + "> - TranslationId <" + ((DBLanguageSystem)lngObj).TranslationId + "> - Text <" + ((DBLanguageSystem)lngObj).Text + "> )"); } } return; } case "selectshow": { LanguageDataObject lngObj = (LanguageDataObject)client.Player.TempProperties.getProperty <object>(LANGUAGEMGR_SEL_LNG_OBJ, null); if (lngObj == null) { DisplayMessage(client, "[Language-Manager] No language object selected!"); } else { DisplayMessage(client, "[Language-Manager] Language object info: Language <" + lngObj.Language + "> - TranslationId <" + lngObj.TranslationId + "> - Text <" + ((DBLanguageSystem)lngObj).Text + ">"); } return; } case "show": { if (args.Length < 4) { DisplayMessage(client, "[Language-Manager] Usage: '/translate show [Language] [TranslationId]'"); } else { LanguageDataObject lngObj = LanguageMgr.GetLanguageDataObject(args[2].ToUpper(), args[3], LanguageDataObject.eTranslationIdentifier.eSystem); if (lngObj == null) { DisplayMessage(client, "[Language-Manager] Can't find language object. ( Language <" + args[2].ToUpper() + "> - TranslationId <" + args[3] + "> )"); } else { DisplayMessage(client, "[Language-Manager] " + ((DBLanguageSystem)lngObj).Text); } } return; } /* * The code works fine, but DAoC does not support a such huge list. * * case "showlist": * { * if (args.Length < 3) * DisplayMessage(client, "aaa"); * else * { #region showall * if (args[2].ToLower() == "showall") * { * IDictionary<string, IList<string>> idLangs = new Dictionary<string, IList<string>>(); * List<string> languages = new List<string>(); * languages.AddRange(LanguageMgr.Languages); * IList<string> data = new List<string>(); * * foreach (string language in LanguageMgr.Translations.Keys) * { * if (!LanguageMgr.Translations[language].ContainsKey(LanguageDataObject.eTranslationIdentifier.eSystem)) * continue; * * data.Add("======== Language <" + language + "> ========\n\n"); * * foreach (LanguageDataObject lngObj in LanguageMgr.Translations[language][LanguageDataObject.eTranslationIdentifier.eSystem]) * { * data.Add("TranslationId: " + lngObj.TranslationId + "\nText: " + ((DBLanguageSystem)lngObj).Text + "\n\n"); * * if (!idLangs.ContainsKey(lngObj.TranslationId)) * { * IList<string> langs = new List<string>(); * langs.Add(lngObj.Language); * idLangs.Add(lngObj.TranslationId, langs); * continue; * } * * if (!idLangs[lngObj.TranslationId].Contains(lngObj.Language)) * idLangs[lngObj.TranslationId].Add(lngObj.Language); * * continue; * } * } * * IDictionary<string, IList<string>> missingLanguageTranslations = new Dictionary<string, IList<string>>(); * * foreach (string translationId in idLangs.Keys) * { * foreach (string language in languages) * { * if (idLangs[translationId].Contains(language)) * continue; * * if (!missingLanguageTranslations.ContainsKey(translationId)) * { * IList<string> langs = new List<string>(); * langs.Add(language); * missingLanguageTranslations.Add(translationId, langs); * continue; * } * * if (!missingLanguageTranslations[translationId].Contains(language)) * missingLanguageTranslations[translationId].Add(language); * * continue; * } * } * * if (missingLanguageTranslations.Count > 0) * { * data.Add("======== Missing language translations ========\n\n"); * * foreach (string translationId in missingLanguageTranslations.Keys) * { * string str = ("TranslationId: " + translationId + "\nLanguages: "); * * foreach (string language in missingLanguageTranslations[translationId]) * str += (language + ","); * * if (str[(str.Length - 1)] == ',') * str = str.Remove(str.Length - 1); * * data.Add(str); * } * } * * client.Out.SendCustomTextWindow("[Language-Manager] Translations", data); // I wish you a merry christmas and a happy new year (2112)! :-) * } #endregion showall * #region language * else * { * if (!LanguageMgr.Languages.Contains(args[2].ToUpper())) * DisplayMessage(client, "aaa"); * else * { * if (!LanguageMgr.Translations[args[2].ToUpper()].ContainsKey(LanguageDataObject.eTranslationIdentifier.eSystem)) * DisplayMessage(client, "aaa"); * else * { * IList<string> data = new List<string>(); * * foreach (LanguageDataObject lngObj in LanguageMgr.Translations[args[2].ToUpper()][LanguageDataObject.eTranslationIdentifier.eSystem]) * data.Add("TranslationId: " + lngObj.TranslationId + "\nText: " + ((DBLanguageSystem)lngObj).Text + "\n\n"); * * client.Out.SendCustomTextWindow("[Language-Manager] Language translations <" + args[2].ToUpper() + ">", data); * } * } * } #endregion language * } * * return; * }*/ default: { DisplaySyntax(client); return; } } }
//static int lastZ=int.MinValue; public void HandlePacket(GameClient client, GSPacketIn packet) { //Tiv: in very rare cases client send 0xA9 packet before sending S<=C 0xE8 player world initialize if ((client.Player.ObjectState != GameObject.eObjectState.Active) || (client.ClientState != GameClient.eClientState.Playing)) { return; } int environmentTick = Environment.TickCount; int packetVersion; if (client.Version > GameClient.eClientVersion.Version171) { packetVersion = 172; } else { packetVersion = 168; } int oldSpeed = client.Player.CurrentSpeed; //read the state of the player packet.Skip(2); //PID ushort data = packet.ReadShort(); int speed = (data & 0x1FF); // if(!GameServer.ServerRules.IsAllowedDebugMode(client) // && (speed > client.Player.MaxSpeed + SPEED_TOL)) if ((data & 0x200) != 0) { speed = -speed; } if (client.Player.IsMezzed || client.Player.IsStunned) { // Nidel: updating client.Player.CurrentSpeed instead of speed client.Player.CurrentSpeed = 0; } else { client.Player.CurrentSpeed = (short)speed; } client.Player.IsStrafing = ((data & 0xe000) != 0); int realZ = packet.ReadShort(); ushort xOffsetInZone = packet.ReadShort(); ushort yOffsetInZone = packet.ReadShort(); ushort currentZoneID; if (packetVersion == 168) { currentZoneID = (ushort)packet.ReadByte(); packet.Skip(1); //0x00 padding for zoneID } else { currentZoneID = packet.ReadShort(); } //Dinberg - Instance considerations. //Now this gets complicated, so listen up! We have told the client a lie when it comes to the zoneID. //As a result, every movement update, they are sending a lie back to us. Two liars could get confusing! //BUT, the lie we sent has a truth to it - the geometry and layout of the zone. As a result, the zones //x and y offsets will still actually be relevant to our current zone. And for the clones to have been //created, there must have been a real zone to begin with, of id == instanceZone.SkinID. //So, although our client is lying to us, and thinks its in another zone, that zone happens to coincide //exactly with the zone we are instancing - and so all the positions still ring true. //Philosophically speaking, its like looking in a mirror and saying 'Am I a reflected, or reflector?' //What it boils down to has no bearing whatsoever on the result of anything, so long as someone sitting //outside of the unvierse knows not to listen to whether you say which you are, and knows the truth to the //answer. Then, he need only know what you are doing ;) Zone newZone = WorldMgr.GetZone(currentZoneID); if (newZone == null) { if (client.Player == null) { return; } if (!client.Player.TempProperties.getProperty("isbeingbanned", false)) { if (log.IsErrorEnabled) { log.Error(client.Player.Name + "'s position in unknown zone! => " + currentZoneID); } GamePlayer player = client.Player; player.TempProperties.setProperty("isbeingbanned", true); player.MoveToBind(); } return; // TODO: what should we do? player lost in space } // move to bind if player fell through the floor if (realZ == 0) { client.Player.MoveTo( (ushort)client.Player.DBCharacter.BindRegion, client.Player.DBCharacter.BindXpos, client.Player.DBCharacter.BindYpos, (ushort)client.Player.DBCharacter.BindZpos, (ushort)client.Player.DBCharacter.BindHeading ); return; } int realX = newZone.XOffset + xOffsetInZone; int realY = newZone.YOffset + yOffsetInZone; bool zoneChange = newZone != client.Player.LastPositionUpdateZone; if (zoneChange) { //If the region changes -> make sure we don't take any falling damage if (client.Player.LastPositionUpdateZone != null && newZone.ZoneRegion.ID != client.Player.LastPositionUpdateZone.ZoneRegion.ID) { client.Player.MaxLastZ = int.MinValue; } // Update water level and diving flag for the new zone client.Out.SendPlayerPositionAndObjectID(); zoneChange = true; /* * "You have entered Burial Tomb." * "Burial Tomb" * "Current area is adjusted for one level 1 player." * "Current area has a 50% instance bonus." */ string description = newZone.Description; string screenDescription = description; LanguageDataObject translation = LanguageMgr.GetTranslation(client.Account.Language, newZone); if (translation != null) { if (!Util.IsEmpty(((DBLanguageZone)translation).Description)) { description = ((DBLanguageZone)translation).Description; } if (!Util.IsEmpty(((DBLanguageZone)translation).ScreenDescription)) { screenDescription = ((DBLanguageZone)translation).ScreenDescription; } } client.Out.SendMessage(LanguageMgr.GetTranslation(client.Account.Language, "PlayerPositionUpdateHandler.Entered", description), eChatType.CT_System, eChatLoc.CL_SystemWindow); client.Out.SendMessage(screenDescription, eChatType.CT_ScreenCenterSmaller, eChatLoc.CL_SystemWindow); client.Player.LastPositionUpdateZone = newZone; } int coordsPerSec = 0; int jumpDetect = 0; int timediff = Environment.TickCount - client.Player.LastPositionUpdateTick; int distance = 0; if (timediff > 0) { distance = client.Player.LastPositionUpdatePoint.GetDistanceTo(new Point3D(realX, realY, realZ)); coordsPerSec = distance * 1000 / timediff; if (distance < 100 && client.Player.LastPositionUpdatePoint.Z > 0) { jumpDetect = realZ - client.Player.LastPositionUpdatePoint.Z; } } #region DEBUG #if OUTPUT_DEBUG_INFO if (client.Player.LastPositionUpdatePoint.X != 0 && client.Player.LastPositionUpdatePoint.Y != 0) { log.Debug(client.Player.Name + ": distance = " + distance + ", speed = " + oldSpeed + ", coords/sec=" + coordsPerSec); } if (jumpDetect > 0) { log.Debug(client.Player.Name + ": jumpdetect = " + jumpDetect); } #endif #endregion DEBUG client.Player.LastPositionUpdateTick = Environment.TickCount; client.Player.LastPositionUpdatePoint.X = realX; client.Player.LastPositionUpdatePoint.Y = realY; client.Player.LastPositionUpdatePoint.Z = realZ; int tolerance = ServerProperties.Properties.CPS_TOLERANCE; if (client.Player.Steed != null && client.Player.Steed.MaxSpeed > 0) { tolerance += client.Player.Steed.MaxSpeed; } else if (client.Player.MaxSpeed > 0) { tolerance += client.Player.MaxSpeed; } if (client.Player.IsJumping) { coordsPerSec = 0; jumpDetect = 0; client.Player.IsJumping = false; } if (client.Player.IsAllowedToFly == false && (coordsPerSec > tolerance || jumpDetect > ServerProperties.Properties.JUMP_TOLERANCE)) { bool isHackDetected = true; if (coordsPerSec > tolerance) { // check to see if CPS time tolerance is exceeded int lastCPSTick = client.Player.TempProperties.getProperty <int>(LASTCPSTICK, 0); if (environmentTick - lastCPSTick > ServerProperties.Properties.CPS_TIME_TOLERANCE) { isHackDetected = false; } } if (isHackDetected) { StringBuilder builder = new StringBuilder(); builder.Append("MOVEHACK_DETECT"); builder.Append(": CharName="); builder.Append(client.Player.Name); builder.Append(" Account="); builder.Append(client.Account.Name); builder.Append(" IP="); builder.Append(client.TcpEndpointAddress); builder.Append(" CPS:="); builder.Append(coordsPerSec); builder.Append(" JT="); builder.Append(jumpDetect); ChatUtil.SendDebugMessage(client, builder.ToString()); if (client.Account.PrivLevel == 1) { GameServer.Instance.LogCheatAction(builder.ToString()); if (ServerProperties.Properties.ENABLE_MOVEDETECT) { if (ServerProperties.Properties.BAN_HACKERS && false) // banning disabled until this technique is proven accurate { DBBannedAccount b = new DBBannedAccount(); b.Author = "SERVER"; b.Ip = client.TcpEndpointAddress; b.Account = client.Account.Name; b.DateBan = DateTime.Now; b.Type = "B"; b.Reason = string.Format("Autoban MOVEHACK:(CPS:{0}, JT:{1}) on player:{2}", coordsPerSec, jumpDetect, client.Player.Name); GameServer.Database.AddObject(b); GameServer.Database.SaveObject(b); string message = ""; message = "You have been auto kicked and banned due to movement hack detection!"; for (int i = 0; i < 8; i++) { client.Out.SendMessage(message, eChatType.CT_Help, eChatLoc.CL_SystemWindow); client.Out.SendMessage(message, eChatType.CT_Help, eChatLoc.CL_ChatWindow); } client.Out.SendPlayerQuit(true); client.Player.SaveIntoDatabase(); client.Player.Quit(true); } else { string message = ""; message = "You have been auto kicked due to movement hack detection!"; for (int i = 0; i < 8; i++) { client.Out.SendMessage(message, eChatType.CT_Help, eChatLoc.CL_SystemWindow); client.Out.SendMessage(message, eChatType.CT_Help, eChatLoc.CL_ChatWindow); } client.Out.SendPlayerQuit(true); client.Player.SaveIntoDatabase(); client.Player.Quit(true); } client.Disconnect(); return; } } } client.Player.TempProperties.setProperty(LASTCPSTICK, environmentTick); } ushort headingflag = packet.ReadShort(); client.Player.Heading = (ushort)(headingflag & 0xFFF); ushort flyingflag = packet.ReadShort(); byte flags = (byte)packet.ReadByte(); if (client.Player.X != realX || client.Player.Y != realY) { client.Player.TempProperties.setProperty(LASTMOVEMENTTICK, client.Player.CurrentRegion.Time); } client.Player.X = realX; client.Player.Y = realY; client.Player.Z = realZ; if (zoneChange) { // update client zone information for waterlevel and diving client.Out.SendPlayerPositionAndObjectID(); } // used to predict current position, should be before // any calculation (like fall damage) client.Player.MovementStartTick = Environment.TickCount; // Begin ---------- New Area System ----------- if (client.Player.CurrentRegion.Time > client.Player.AreaUpdateTick) // check if update is needed { IList oldAreas = client.Player.CurrentAreas; // Because we may be in an instance we need to do the area check from the current region // rather than relying on the zone which is in the skinned region. - Tolakram IList newAreas = client.Player.CurrentRegion.GetAreasOfZone(newZone, client.Player); // Check for left areas if (oldAreas != null) { foreach (IArea area in oldAreas) { if (!newAreas.Contains(area)) { area.OnPlayerLeave(client.Player); } } } // Check for entered areas foreach (IArea area in newAreas) { if (oldAreas == null || !oldAreas.Contains(area)) { area.OnPlayerEnter(client.Player); } } // set current areas to new one... client.Player.CurrentAreas = newAreas; client.Player.AreaUpdateTick = client.Player.CurrentRegion.Time + 2000; // update every 2 seconds } // End ---------- New Area System ----------- client.Player.TargetInView = ((flags & 0x10) != 0); client.Player.GroundTargetInView = ((flags & 0x08) != 0); client.Player.IsTorchLighted = ((flags & 0x80) != 0); //7 6 5 4 3 2 1 0 //15 14 13 12 11 10 9 8 // 1 1 const string SHLASTUPDATETICK = "SHPLAYERPOSITION_LASTUPDATETICK"; const string SHLASTFLY = "SHLASTFLY_STRING"; const string SHLASTSTATUS = "SHLASTSTATUS_STRING"; int SHlastTick = client.Player.TempProperties.getProperty <int>(SHLASTUPDATETICK); int SHlastFly = client.Player.TempProperties.getProperty <int>(SHLASTFLY); int SHlastStatus = client.Player.TempProperties.getProperty <int>(SHLASTSTATUS); int SHcount = client.Player.TempProperties.getProperty <int>(SHSPEEDCOUNTER); int status = (data & 0x1FF ^ data) >> 8; int fly = (flyingflag & 0x1FF ^ flyingflag) >> 8; if (client.Player.IsJumping) { SHcount = 0; } if (SHlastTick != 0 && SHlastTick != environmentTick) { if (((SHlastStatus == status || (status & 0x8) == 0)) && ((fly & 0x80) != 0x80) && (SHlastFly == fly || (SHlastFly & 0x10) == (fly & 0x10) || !((((SHlastFly & 0x10) == 0x10) && ((fly & 0x10) == 0x0) && (flyingflag & 0x7FF) > 0)))) { if ((environmentTick - SHlastTick) < 400) { SHcount++; if (SHcount > 1 && client.Account.PrivLevel > 1) { //Apo: ?? no idea how to name the first parameter for language translation: 1: ??, 2: {detected} ?, 3: {count} ? client.Out.SendMessage(string.Format("SH: ({0}) detected: {1}, count {2}", 500 / (environmentTick - SHlastTick), environmentTick - SHlastTick, SHcount), eChatType.CT_Staff, eChatLoc.CL_SystemWindow); } if (SHcount % 5 == 0) { StringBuilder builder = new StringBuilder(); builder.Append("TEST_SH_DETECT["); builder.Append(SHcount); builder.Append("] ("); builder.Append(environmentTick - SHlastTick); builder.Append("): CharName="); builder.Append(client.Player.Name); builder.Append(" Account="); builder.Append(client.Account.Name); builder.Append(" IP="); builder.Append(client.TcpEndpointAddress); GameServer.Instance.LogCheatAction(builder.ToString()); if (client.Account.PrivLevel > 1) { client.Out.SendMessage("SH: Logging SH cheat.", eChatType.CT_Damaged, eChatLoc.CL_SystemWindow); if (SHcount >= ServerProperties.Properties.SPEEDHACK_TOLERANCE) { client.Out.SendMessage("SH: Player would have been banned!", eChatType.CT_Damaged, eChatLoc.CL_SystemWindow); } } if ((client.Account.PrivLevel == 1) && SHcount >= ServerProperties.Properties.SPEEDHACK_TOLERANCE) { if (ServerProperties.Properties.BAN_HACKERS) { DBBannedAccount b = new DBBannedAccount(); b.Author = "SERVER"; b.Ip = client.TcpEndpointAddress; b.Account = client.Account.Name; b.DateBan = DateTime.Now; b.Type = "B"; b.Reason = string.Format("Autoban SH:({0},{1}) on player:{2}", SHcount, environmentTick - SHlastTick, client.Player.Name); GameServer.Database.AddObject(b); GameServer.Database.SaveObject(b); string message = ""; message = "You have been auto kicked and banned for speed hacking!"; for (int i = 0; i < 8; i++) { client.Out.SendMessage(message, eChatType.CT_Help, eChatLoc.CL_SystemWindow); client.Out.SendMessage(message, eChatType.CT_Help, eChatLoc.CL_ChatWindow); } client.Out.SendPlayerQuit(true); client.Player.SaveIntoDatabase(); client.Player.Quit(true); } else { string message = ""; message = "You have been auto kicked for speed hacking!"; for (int i = 0; i < 8; i++) { client.Out.SendMessage(message, eChatType.CT_Help, eChatLoc.CL_SystemWindow); client.Out.SendMessage(message, eChatType.CT_Help, eChatLoc.CL_ChatWindow); } client.Out.SendPlayerQuit(true); client.Player.SaveIntoDatabase(); client.Player.Quit(true); } client.Disconnect(); return; } } } else { SHcount = 0; } SHlastTick = environmentTick; } } else { SHlastTick = environmentTick; } int state = ((data >> 10) & 7); client.Player.IsClimbing = (state == 7); client.Player.IsSwimming = (state == 1); if (state == 3 && client.Player.TempProperties.getProperty <bool>(GamePlayer.DEBUG_MODE_PROPERTY, false) == false && client.Player.IsAllowedToFly == false) //debugFly on, but player not do /debug on (hack) { StringBuilder builder = new StringBuilder(); builder.Append("HACK_FLY"); builder.Append(": CharName="); builder.Append(client.Player.Name); builder.Append(" Account="); builder.Append(client.Account.Name); builder.Append(" IP="); builder.Append(client.TcpEndpointAddress); GameServer.Instance.LogCheatAction(builder.ToString()); { if (ServerProperties.Properties.BAN_HACKERS) { DBBannedAccount b = new DBBannedAccount(); b.Author = "SERVER"; b.Ip = client.TcpEndpointAddress; b.Account = client.Account.Name; b.DateBan = DateTime.Now; b.Type = "B"; b.Reason = string.Format("Autoban flying hack: on player:{0}", client.Player.Name); GameServer.Database.AddObject(b); GameServer.Database.SaveObject(b); } string message = ""; message = "Client Hack Detected!"; for (int i = 0; i < 6; i++) { client.Out.SendMessage(message, eChatType.CT_System, eChatLoc.CL_SystemWindow); client.Out.SendMessage(message, eChatType.CT_System, eChatLoc.CL_ChatWindow); } client.Out.SendPlayerQuit(true); client.Disconnect(); return; } } SHlastFly = fly; SHlastStatus = status; client.Player.TempProperties.setProperty(SHLASTUPDATETICK, SHlastTick); client.Player.TempProperties.setProperty(SHLASTFLY, SHlastFly); client.Player.TempProperties.setProperty(SHLASTSTATUS, SHlastStatus); client.Player.TempProperties.setProperty(SHSPEEDCOUNTER, SHcount); lock (client.Player.LastUniqueLocations) { GameLocation[] locations = client.Player.LastUniqueLocations; GameLocation loc = locations[0]; if (loc.X != realX || loc.Y != realY || loc.Z != realZ || loc.RegionID != client.Player.CurrentRegionID) { loc = locations[locations.Length - 1]; Array.Copy(locations, 0, locations, 1, locations.Length - 1); locations[0] = loc; loc.X = realX; loc.Y = realY; loc.Z = realZ; loc.Heading = client.Player.Heading; loc.RegionID = client.Player.CurrentRegionID; } } //**************// //FALLING DAMAGE// //**************// if (GameServer.ServerRules.CanTakeFallDamage(client.Player) && client.Player.IsSwimming == false) { int maxLastZ = client.Player.MaxLastZ; /* Are we on the ground? */ if ((flyingflag >> 15) != 0) { int safeFallLevel = client.Player.GetAbilityLevel(Abilities.SafeFall); int fallSpeed = (flyingflag & 0xFFF) - 100 * safeFallLevel; // 0x7FF fall speed and 0x800 bit = fall speed overcaped int fallMinSpeed = 400; int fallDivide = 6; if (client.Version >= GameClient.eClientVersion.Version188) { fallMinSpeed = 500; fallDivide = 15; } int fallPercent = Math.Min(99, (fallSpeed - (fallMinSpeed + 1)) / fallDivide); if (fallSpeed > fallMinSpeed) { client.Out.SendMessage(LanguageMgr.GetTranslation(client.Account.Language, "PlayerPositionUpdateHandler.FallingDamage"), eChatType.CT_Damaged, eChatLoc.CL_SystemWindow); client.Player.CalcFallDamage(fallPercent); } client.Player.MaxLastZ = client.Player.Z; } else { // always set Z if on the ground if (flyingflag == 0) { client.Player.MaxLastZ = client.Player.Z; } // set Z if in air and higher than old Z else if (maxLastZ < client.Player.Z) { client.Player.MaxLastZ = client.Player.Z; } } } //**************// byte[] con168 = packet.ToArray(); //Riding is set here! if (client.Player.Steed != null && client.Player.Steed.ObjectState == GameObject.eObjectState.Active) { client.Player.Heading = client.Player.Steed.Heading; con168[2] = 0x18; // Set ride flag 00011000 con168[3] = 0; // player speed = 0 while ride con168[12] = (byte)(client.Player.Steed.ObjectID >> 8); //heading = steed ID con168[13] = (byte)(client.Player.Steed.ObjectID & 0xFF); con168[14] = (byte)0; con168[15] = (byte)(client.Player.Steed.RiderSlot(client.Player)); // there rider slot this player } else if (!client.Player.IsAlive) { con168[2] &= 0xE3; //11100011 con168[2] |= 0x14; //Set dead flag 00010100 } //diving is set here con168[16] &= 0xFB; //11 11 10 11 if ((con168[16] & 0x02) != 0x00) { client.Player.IsDiving = true; con168[16] |= 0x04; } else { client.Player.IsDiving = false; } con168[16] &= 0xFC; //11 11 11 00 cleared Wireframe & Stealth bits if (client.Player.IsWireframe) { con168[16] |= 0x01; } //stealth is set here if (client.Player.IsStealthed) { con168[16] |= 0x02; } con168[17] = (byte)((con168[17] & 0x80) | client.Player.HealthPercent); // zone ID has changed in 1.72, fix bytes 11 and 12 byte[] con172 = (byte[])con168.Clone(); if (packetVersion == 168) { // client sent v168 pos update packet, fix 172 version con172[10] = 0; con172[11] = con168[10]; } else { // client sent v172 pos update packet, fix 168 version con168[10] = con172[11]; con168[11] = 0; } GSUDPPacketOut outpak168 = new GSUDPPacketOut(client.Out.GetPacketCode(eServerPackets.PlayerPosition)); //Now copy the whole content of the packet outpak168.Write(con168, 0, 18 /*con168.Length*/); outpak168.WritePacketLength(); GSUDPPacketOut outpak172 = new GSUDPPacketOut(client.Out.GetPacketCode(eServerPackets.PlayerPosition)); //Now copy the whole content of the packet outpak172.Write(con172, 0, 18 /*con172.Length*/); outpak172.WritePacketLength(); // byte[] pak168 = outpak168.GetBuffer(); // byte[] pak172 = outpak172.GetBuffer(); // outpak168 = null; // outpak172 = null; GSUDPPacketOut outpak190 = null; GSUDPPacketOut outpak1112 = new GSUDPPacketOut(client.Out.GetPacketCode(eServerPackets.PlayerPosition)); outpak1112.Write(con172, 0, 18 /*con172.Length*/); outpak1112.WriteByte(client.Player.ManaPercent); outpak1112.WriteByte(client.Player.EndurancePercent); outpak1112.WriteByte((byte)(client.Player.RPFlag ? 1 : 0)); outpak1112.WriteByte(0); //outpak1112.WriteByte((con168.Length == 22) ? con168[21] : (byte)0); outpak1112.WritePacketLength(); foreach (GamePlayer player in client.Player.GetPlayersInRadius(WorldMgr.VISIBILITY_DISTANCE)) { if (player == null) { continue; } //No position updates for ourselves if (player == client.Player) { // Update Player Cache (Client sending Packet is admitting he's already having it) player.Client.GameObjectUpdateArray[new Tuple <ushort, ushort>(client.Player.CurrentRegionID, (ushort)client.Player.ObjectID)] = GameTimer.GetTickCount(); continue; } //no position updates in different houses if ((client.Player.InHouse || player.InHouse) && player.CurrentHouse != client.Player.CurrentHouse) { continue; } if (client.Player.MinotaurRelic != null) { MinotaurRelic relic = client.Player.MinotaurRelic; if (!relic.Playerlist.Contains(player) && player != client.Player) { relic.Playerlist.Add(player); player.Out.SendMinotaurRelicWindow(client.Player, client.Player.MinotaurRelic.Effect, true); } } if (!client.Player.IsStealthed || player.CanDetect(client.Player)) { // Update Player Cache player.Client.GameObjectUpdateArray[new Tuple <ushort, ushort>(client.Player.CurrentRegionID, (ushort)client.Player.ObjectID)] = GameTimer.GetTickCount(); //forward the position packet like normal! if (player.Client.Version >= GameClient.eClientVersion.Version1112) { player.Out.SendUDPRaw(outpak1112); } else if (player.Client.Version >= GameClient.eClientVersion.Version190) { if (outpak190 == null) { outpak190 = new GSUDPPacketOut(client.Out.GetPacketCode(eServerPackets.PlayerPosition)); outpak190.Write(con172, 0, 18 /*con172.Length*/); outpak190.WriteByte(client.Player.ManaPercent); outpak190.WriteByte(client.Player.EndurancePercent); outpak190.FillString(client.Player.CharacterClass.Name, 32); // roleplay flag, if == 1, show name (RP) with gray color if (client.Player.RPFlag) { outpak190.WriteByte(1); } else { outpak190.WriteByte(0); } outpak190.WriteByte((con168.Length == 54) ? con168[53] : (byte)0); // send last byte for 190+ packets outpak190.WritePacketLength(); } player.Out.SendUDPRaw(outpak190); } else if (player.Client.Version >= GameClient.eClientVersion.Version172) { player.Out.SendUDPRaw(outpak172); } else { player.Out.SendUDPRaw(outpak168); } } else { player.Out.SendObjectDelete(client.Player); //remove the stealthed player from view } } if (client.Player.CharacterClass.ID == (int)eCharacterClass.Warlock) { //Send Chamber effect client.Player.Out.SendWarlockChamberEffect(client.Player); } //handle closing of windows //trade window if (client.Player.TradeWindow != null) { if (client.Player.TradeWindow.Partner != null) { if (!client.Player.IsWithinRadius(client.Player.TradeWindow.Partner, WorldMgr.GIVE_ITEM_DISTANCE)) { client.Player.TradeWindow.CloseTrade(); } } } }