public override IList GetExamineMessages(GamePlayer player) { /* * You select the Keep Gate. It belongs to your realm. * You target [the Keep Gate] * * You select the Keep Gate. It belongs to an enemy realm and can be attacked! * You target [the Keep Gate] * * You select the Postern Door. It belongs to an enemy realm! * You target [the Postern Door] */ IList list = base.GetExamineMessages(player); string text = "You select the " + Name + "."; if (!GameServer.KeepManager.IsEnemy(this, player)) { text = text + " It belongs to your realm."; } else { if (IsAttackableDoor) { text = text + " It belongs to an enemy realm and can be attacked!"; } else { text = text + " It belongs to an enemy realm!"; } } list.Add(text); ChatUtil.SendDebugMessage(player, "Health = " + Health); if (IsAttackableDoor) { // Attempt to fix issue where some players see door as closed when it should be broken open // if you target a door it will re-broadcast it's state if (Health <= 0 && State != eDoorState.Open) { State = eDoorState.Open; BroadcastDoorStatus(); } else if (State == eDoorState.Open) { player.SendDoorUpdate(this, true); } } return(list); }
public override void OnPlayerEnter(GamePlayer player) { bool showText = false; if (m_dataQuest != null) { ChatUtil.SendDebugMessage(player, "Entered QuestSearchArea for DataQuest ID:" + m_dataQuest.ID + ", Step " + Step); // first check active data quests foreach (AbstractQuest quest in player.QuestList) { if (quest is DataQuest) { if ((quest as DataQuest).ID == m_dataQuest.ID && quest.Step == Step && m_popupText != string.Empty) { showText = true; } } } // next check for searches that start a dataquest if (Step == 0 && DataQuest.CheckQuestQualification(player)) { showText = true; } } else { ChatUtil.SendDebugMessage(player, "Entered QuestSearchArea for " + m_questType.Name + ", Step " + Step); // popup a dialog telling the player they should search here if (player.IsDoingQuest(m_questType) != null && player.IsDoingQuest(m_questType).Step == m_validStep && PopupText != string.Empty) { showText = true; } } if (showText) { player.Out.SendDialogBox(eDialogCode.SimpleWarning, 0, 0, 0, 0, eDialogType.Ok, true, m_popupText); } }
public void HandlePacket(GameClient client, GSPacketIn packet) { ushort jumpSpotID = packet.ReadShort(); eRealm targetRealm = client.Player.Realm; if (client.Player.CurrentRegion.Expansion == (int)eClientExpansion.TrialsOfAtlantis && client.Player.CurrentZone.Realm != eRealm.None) { // if we are in TrialsOfAtlantis then base the target jump on the current region realm instead of the players realm // this is only used if zone table has the proper realms defined, otherwise it reverts to old behavior - Tolakram targetRealm = client.Player.CurrentZone.Realm; } var zonePoint = GameServer.Database.SelectObjects <ZonePoint>("`Id` = @Id AND (`Realm` = @Realm OR `Realm` = @DefaultRealm OR `Realm` IS NULL)", new [] { new QueryParameter("@Id", jumpSpotID), new QueryParameter("@Realm", (byte)targetRealm), new QueryParameter("@DefaultRealm", 0) }).FirstOrDefault(); if (zonePoint == null || zonePoint.TargetRegion == 0) { ChatUtil.SendDebugMessage(client, "Invalid Jump (ZonePoint table): [" + jumpSpotID + "]" + ((zonePoint == null) ? ". Entry missing!" : ". TargetRegion is 0!")); zonePoint = new ZonePoint(); zonePoint.Id = jumpSpotID; } if (client.Account.PrivLevel > 1) { client.Out.SendMessage("JumpSpotID = " + jumpSpotID, eChatType.CT_System, eChatLoc.CL_SystemWindow); client.Out.SendMessage("ZonePoint Target: Region = " + zonePoint.TargetRegion + ", ClassType = '" + zonePoint.ClassType + "'", eChatType.CT_System, eChatLoc.CL_SystemWindow); } //Dinberg: Fix - some jump points are handled code side, such as instances. //As such, region MAY be zero in the database, so this causes an issue. if (zonePoint.TargetRegion != 0) { Region reg = WorldMgr.GetRegion(zonePoint.TargetRegion); if (reg != null) { // check for target region disabled if player is in a standard region // otherwise the custom region should handle OnZonePoint for this check if (client.Player.CurrentRegion.IsCustom == false && reg.IsDisabled) { if ((client.Player.Mission is TaskDungeonMission && (client.Player.Mission as TaskDungeonMission).TaskRegion.Skin == reg.Skin) == false) { client.Out.SendMessage("This region has been disabled!", eChatType.CT_System, eChatLoc.CL_SystemWindow); if (client.Account.PrivLevel == 1) { return; } } } } } // Allow the region to either deny exit or handle the zonepoint in a custom way if (client.Player.CurrentRegion.OnZonePoint(client.Player, zonePoint) == false) { return; } //check caps for battleground Battleground bg = GameServer.KeepManager.GetBattleground(zonePoint.TargetRegion); if (bg != null) { if (client.Player.Level < bg.MinLevel && client.Player.Level > bg.MaxLevel && client.Player.RealmLevel >= bg.MaxRealmLevel) { return; } } IJumpPointHandler customHandler = null; if (string.IsNullOrEmpty(zonePoint.ClassType) == false) { customHandler = (IJumpPointHandler)m_customJumpPointHandlers[zonePoint.ClassType]; // check for db change to update cached handler if (customHandler != null && customHandler.GetType().FullName != zonePoint.ClassType) { customHandler = null; } if (customHandler == null) { //Dinberg - Instances need to use a special handler. This is because some instances will result //in duplicated zonepoints, such as if Tir Na Nog were to be instanced for a quest. string type = (client.Player.CurrentRegion.IsInstance) ? "DOL.GS.ServerRules.InstanceDoorJumpPoint" : zonePoint.ClassType; Type t = ScriptMgr.GetType(type); if (t == null) { Log.ErrorFormat("jump point {0}: class {1} not found!", zonePoint.Id, zonePoint.ClassType); } else if (!typeof(IJumpPointHandler).IsAssignableFrom(t)) { Log.ErrorFormat("jump point {0}: class {1} must implement IJumpPointHandler interface!", zonePoint.Id, zonePoint.ClassType); } else { try { customHandler = (IJumpPointHandler)Activator.CreateInstance(t); } catch (Exception e) { customHandler = null; Log.Error( string.Format("jump point {0}: error creating a new instance of jump point handler {1}", zonePoint.Id, zonePoint.ClassType), e); } } } if (customHandler != null) { m_customJumpPointHandlers[zonePoint.ClassType] = customHandler; } } new RegionChangeRequestHandler(client.Player, zonePoint, customHandler).Start(1); }
/// <summary> /// door index which is unique /// </summary> public void HandlePacket(GameClient client, GSPacketIn packet) { var doorID = (int)packet.ReadInt(); m_handlerDoorID = doorID; var doorState = (byte)packet.ReadByte(); int doorType = doorID / 100000000; int radius = Properties.WORLD_PICKUP_DISTANCE * 2; int zoneDoor = doorID / 1000000; string debugText = ""; // For ToA the client always sends the same ID so we need to construct an id using the current zone if (client.Player.CurrentRegion.Expansion == (int)eClientExpansion.TrialsOfAtlantis) { debugText = $"ToA DoorID:{doorID} "; doorID -= zoneDoor * 1000000; zoneDoor = client.Player.CurrentZone.ID; doorID += zoneDoor * 1000000; m_handlerDoorID = doorID; // experimental to handle a few odd TOA door issues if (client.Player.CurrentRegion.IsDungeon) { radius *= 4; } } // debug text if (client.Account.PrivLevel > 1 || Properties.ENABLE_DEBUG) { if (doorType == 7) { int ownerKeepId = (doorID / 100000) % 1000; int towerNum = (doorID / 10000) % 10; int keepID = ownerKeepId + towerNum * 256; int componentID = (doorID / 100) % 100; int doorIndex = doorID % 10; client.Out.SendDebugMessage($"Keep Door ID:{doorID} state:{doorState} (Owner Keep:{ownerKeepId} KeepID:{keepID} ComponentID:{componentID} DoorIndex:{doorIndex} TowerNumber:{towerNum})"); if (keepID > 255 && ownerKeepId < 10) { ChatUtil.SendDebugMessage(client, "Warning: Towers with an Owner Keep ID < 10 will have untargetable doors!"); } } else if (doorType == 9) { int doorIndex = doorID - doorType * 10000000; client.Out.SendDebugMessage($"House DoorID:{doorID} state:{doorState} (doorType:{doorType} doorIndex:{doorIndex})"); } else { int fixture = (doorID - zoneDoor * 1000000); int fixturePiece = fixture; fixture /= 100; fixturePiece = fixturePiece - fixture * 100; client.Out.SendDebugMessage($"{debugText}DoorID:{doorID} state:{doorState} zone:{zoneDoor} fixture:{fixture} fixturePiece:{fixturePiece} Type:{doorType}"); } } if (client.Player.TargetObject is GameDoor target && !client.Player.IsWithinRadius(target, radius)) { client.Player.Out.SendMessage("You are too far to open this door", eChatType.CT_Important, eChatLoc.CL_SystemWindow); return; } var door = DOLDB <DBDoor> .SelectObject(DB.Column(nameof(DBDoor.InternalID)).IsEqualTo(doorID)); if (door != null) { if (doorType == 7 || doorType == 9) { new ChangeDoorAction(client.Player, doorID, doorState, radius).Start(1); return; } if (client.Account.PrivLevel == 1) { if (door.Locked == 0) { if (door.Health == 0) { new ChangeDoorAction(client.Player, doorID, doorState, radius).Start(1); return; } if (GameServer.Instance.Configuration.ServerType == eGameServerType.GST_PvP || GameServer.Instance.Configuration.ServerType == eGameServerType.GST_PvE) { if (door.Realm != 0) { new ChangeDoorAction(client.Player, doorID, doorState, radius).Start(1); return; } } else { if (client.Player.Realm == (eRealm)door.Realm || door.Realm == 6) { new ChangeDoorAction(client.Player, doorID, doorState, radius).Start(1); return; } } } } else if (client.Account.PrivLevel > 1) { client.Out.SendDebugMessage("GM: Forcing locked door open."); new ChangeDoorAction(client.Player, doorID, doorState, radius).Start(1); return; } } else // door == null { if (doorType != 9 && client.Account.PrivLevel > 1 && client.Player.CurrentRegion.IsInstance == false) { if (client.Player.TempProperties.getProperty(DoorMgr.WANT_TO_ADD_DOORS, false)) { client.Player.Out.SendCustomDialog( "This door is not in the database. Place yourself nearest to this door and click Accept to add it.", AddingDoor); } else { client.Player.Out.SendMessage( "This door is not in the database. Use '/door show' to enable the add door dialog when targeting doors.", eChatType.CT_Important, eChatLoc.CL_SystemWindow); } } new ChangeDoorAction(client.Player, doorID, doorState, radius).Start(1); 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.BindRegion, client.Player.BindXpos, client.Player.BindYpos, (ushort)client.Player.BindZpos, (ushort)client.Player.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; var translation = client.GetTranslation(newZone) as DBLanguageZone; if (translation != null) { if (!Util.IsEmpty(translation.Description)) { description = translation.Description; } if (!Util.IsEmpty(translation.ScreenDescription)) { screenDescription = 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 { var 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 var 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(); } } } }
//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 oldSpeed = client.Player.CurrentSpeed; int newPlayerX = (int)packet.ReadFloatLowEndian(); int newPlayerY = (int)packet.ReadFloatLowEndian(); int newPlayerZ = (int)packet.ReadFloatLowEndian(); int newPlayerSpeed = (int)packet.ReadFloatLowEndian(); int newPlayerZSpeed = (int)packet.ReadFloatLowEndian(); ushort sessionID = packet.ReadShort(); ushort currentZoneID = packet.ReadShort(); ushort playerState = packet.ReadShort(); ushort fallingDMG = packet.ReadShort(); ushort newHeading = packet.ReadShort(); byte playerAction = (byte)packet.ReadByte(); packet.Skip(2); // unknown bytes x2 byte playerHealth = (byte)packet.ReadByte(); // two trailing bytes, no data //int speed = (newPlayerSpeed & 0x1FF); //Flags1 = (eFlags1)playerState; //Flags2 = (eFlags2)playerAction; if (client.Player.IsMezzed || client.Player.IsStunned) { // Nidel: updating client.Player.CurrentSpeed instead of speed client.Player.CurrentSpeed = 0; } else { client.Player.CurrentSpeed = (short)newPlayerSpeed; } /* * client.Player.IsStrafing = Flags1 == eFlags1.STRAFELEFT || Flags1 == eFlags1.STRAFERIGHT; * client.Player.IsDiving = Flags2 == eFlags2.DIVING ? true : false; * client.Player.IsSwimming = Flags1 == eFlags1.SWIMMING ? true : false; * if (client.Player.IsRiding) * Flags1 = eFlags1.RIDING; * client.Player.IsClimbing = Flags1 == eFlags1.CLIMBING ? true : false; * if (!client.Player.IsAlive) * Flags1 = eFlags1.DEAD;*/ client.Player.IsJumping = ((playerAction & 0x40) != 0); client.Player.IsStrafing = ((playerState & 0xe000) != 0); 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 (newPlayerZ == 0) { client.Player.MoveTo( (ushort)client.Player.BindRegion, client.Player.BindXpos, client.Player.BindYpos, (ushort)client.Player.BindZpos, (ushort)client.Player.BindHeading ); return; } //int realX = newPlayerX; //int realY = newPlayerY; //int realZ = newPlayerZ; 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; var translation = client.GetTranslation(newZone) as DBLanguageZone; if (translation != null) { if (!Util.IsEmpty(translation.Description)) { description = translation.Description; } if (!Util.IsEmpty(translation.ScreenDescription)) { screenDescription = 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(newPlayerX, newPlayerY, newPlayerZ)); coordsPerSec = distance * 1000 / timediff; if (distance < 100 && client.Player.LastPositionUpdatePoint.Z > 0) { jumpDetect = newPlayerZ - client.Player.LastPositionUpdatePoint.Z; } } client.Player.LastPositionUpdateTick = Environment.TickCount; client.Player.LastPositionUpdatePoint.X = newPlayerX; client.Player.LastPositionUpdatePoint.Y = newPlayerY; client.Player.LastPositionUpdatePoint.Z = newPlayerZ; 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 && (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); } //client.Player.Heading = (ushort)(newHeading & 0xFFF); //patch 0024 expermental if (client.Player.X != newPlayerX || client.Player.Y != newPlayerY) { client.Player.TempProperties.setProperty(LASTMOVEMENTTICK, client.Player.CurrentRegion.Time); } //patch 0024 expermental //client.Player.X = realX; //client.Player.Y = realY; //client.Player.Z = realZ; client.Player.SetCoords(newPlayerX, newPlayerY, newPlayerZ, (ushort)(newHeading & 0xFFF)); //patch 0024 expermental 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; experimental 0024 // Begin ---------- New Area System ----------- if (client.Player.CurrentRegion.Time > client.Player.AreaUpdateTick) // check if update is needed { var 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 var 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.IsDiving = ((playerAction & 0x02) != 0); client.Player.TargetInView = ((playerAction & 0x30) != 0); client.Player.GroundTargetInView = ((playerAction & 0x08) != 0); client.Player.IsTorchLighted = ((playerAction & 0x80) != 0); // patch 0069 player diving is 0x02, but will broadcast to other players as 0x04 // if player has a pet summoned, player action is sent by client as 0x04, but sending to other players this is skipped client.Player.IsDiving = ((playerAction & 0x02) != 0); int state = ((playerState >> 10) & 7); client.Player.IsClimbing = (state == 7); client.Player.IsSwimming = (state == 1); //int status = (data & 0x1FF ^ data) >> 8; //int fly = (flyingflag & 0x1FF ^ flyingflag) >> 8; if (state == 3 && client.Player.TempProperties.getProperty <bool>(GamePlayer.DEBUG_MODE_PROPERTY, false) == false && !client.Player.IsAllowedToFly) //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; } } lock (client.Player.LastUniqueLocations) { GameLocation[] locations = client.Player.LastUniqueLocations; GameLocation loc = locations[0]; if (loc.X != newPlayerX || loc.Y != newPlayerY || loc.Z != newPlayerZ || loc.RegionID != client.Player.CurrentRegionID) { loc = locations[locations.Length - 1]; Array.Copy(locations, 0, locations, 1, locations.Length - 1); locations[0] = loc; loc.X = newPlayerX; loc.Y = newPlayerY; loc.Z = newPlayerZ; loc.Heading = client.Player.Heading; loc.RegionID = client.Player.CurrentRegionID; } } //FALLING DAMAGE if (GameServer.ServerRules.CanTakeFallDamage(client.Player) && !client.Player.IsSwimming) { try { int maxLastZ = client.Player.MaxLastZ; // Are we on the ground? if ((fallingDMG >> 15) != 0) { int safeFallLevel = client.Player.GetAbilityLevel(Abilities.SafeFall); int fallSpeed = (newPlayerZSpeed * -1) - (100 * safeFallLevel); int fallDivide = 15; int fallPercent = Math.Min(99, (fallSpeed - (501)) / fallDivide); if (fallSpeed > 500) { client.Out.SendMessage(LanguageMgr.GetTranslation(client.Account.Language, "PlayerPositionUpdateHandler.FallingDamage"), eChatType.CT_Damaged, eChatLoc.CL_SystemWindow); client.Out.SendMessage(string.Format("You take {0}% of you max hits in damage.", fallPercent), eChatType.CT_Damaged, eChatLoc.CL_SystemWindow); client.Out.SendMessage("You lose endurance", eChatType.CT_Damaged, eChatLoc.CL_SystemWindow); client.Player.CalcFallDamage(fallPercent); } client.Player.MaxLastZ = client.Player.Z; } else { if (maxLastZ < client.Player.Z || client.Player.IsRiding || newPlayerZSpeed > -150) // is riding, for dragonflys { client.Player.MaxLastZ = client.Player.Z; } } } catch { log.Warn("error when attempting to calculate fall damage"); } } if (client.Player.Steed != null && client.Player.Steed.ObjectState == GameObject.eObjectState.Active) { client.Player.Heading = client.Player.Steed.Heading; newHeading = (ushort)client.Player.Steed.ObjectID; // test patch 0064 //playerState |= 0x1800; } else if ((playerState >> 10) == 4) // patch 0062 fix bug on release preventing players from receiving res sickness { client.Player.IsSitting = true; } /*else if ((playerState & 0x1000) != 0) //player sitting when releasing on death, dead = 0x1400 * { * client.Player.IsSitting = true; * }*/ GSUDPPacketOut outpak = new GSUDPPacketOut(client.Out.GetPacketCode(eServerPackets.PlayerPosition)); //patch 0069 test to fix player swim out byte flag byte playerOutAction = 0x00; if (client.Player.IsDiving) { playerOutAction |= 0x04; } if (client.Player.TargetInView) { playerOutAction |= 0x30; } if (client.Player.GroundTargetInView) { playerOutAction |= 0x08; } if (client.Player.IsTorchLighted) { playerOutAction |= 0x80; } //stealth is set here if (client.Player.IsStealthed) { playerState |= 0x0200; } outpak.WriteFloatLowEndian(newPlayerX); outpak.WriteFloatLowEndian(newPlayerY); outpak.WriteFloatLowEndian(newPlayerZ); outpak.WriteFloatLowEndian(newPlayerSpeed); outpak.WriteFloatLowEndian(newPlayerZSpeed); outpak.WriteShort(sessionID); outpak.WriteShort(currentZoneID); outpak.WriteShort(playerState); outpak.WriteShort(0); // fall damage flag, dont need to send it outpak.WriteShort(newHeading); outpak.WriteByte(playerOutAction); outpak.WriteByte((byte)(client.Player.RPFlag ? 1 : 0)); outpak.WriteByte(0); outpak.WriteByte((byte)(client.Player.HealthPercent + (client.Player.AttackState ? 0x80 : 0))); outpak.WriteByte(client.Player.ManaPercent); outpak.WriteByte(client.Player.EndurancePercent); //Now copy the whole content of the packet //outpak1119.Write(pak1119, 0, 36); outpak.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; } /* patch 0068 no minotaur logic * 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 // test patch remove players in cache 0065 //player.Client.GameObjectUpdateArray[new Tuple<ushort, ushort>(client.Player.CurrentRegionID, (ushort)client.Player.ObjectID)] = GameTimer.GetTickCount(); player.Out.SendUDPRaw(outpak); } else { player.Out.SendObjectDelete(client.Player); //remove the stealthed player from view } } //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(); } } } }
public void HandlePacket(GameClient client, GSPacketIn packet) { try { packet.ReadByte(); // 1=Money 0=Item (?) int slot = packet.ReadByte(); // Item/money slot ushort housenumber = packet.ReadShort(); // N° of house packet.ReadByte(); // unknown _position = (byte)packet.ReadByte(); int method = packet.ReadByte(); // 2=Wall 3=Floor int rotation = packet.ReadByte(); // garden items only var xpos = (short)packet.ReadShort(); // x for inside objs var ypos = (short)packet.ReadShort(); // y for inside objs. ChatUtil.SendDebugMessage(client, $"HousingPlaceItem: slot: {slot}, position: {_position}, method: {method}, xpos: {xpos}, ypos: {ypos}"); if (client.Player == null) { return; } // house must exist House house = HouseMgr.GetHouse(client.Player.CurrentRegionID, housenumber); if (house == null) { client.Player.Out.SendInventorySlotsUpdate(null); return; } if (slot >= 244 && slot <= 248) // money { // check that player has permission to pay rent if (!house.CanPayRent(client.Player)) { client.Out.SendInventorySlotsUpdate(new[] { slot }); return; } long moneyToAdd = _position; switch (slot) { case 248: moneyToAdd *= 1; break; case 247: moneyToAdd *= 100; break; case 246: moneyToAdd *= 10000; break; case 245: moneyToAdd *= 10000000; break; case 244: moneyToAdd *= 10000000000; break; } client.Player.TempProperties.setProperty(HousingConstants.MoneyForHouseRent, moneyToAdd); client.Player.TempProperties.setProperty(HousingConstants.HouseForHouseRent, house); client.Player.Out.SendInventorySlotsUpdate(null); client.Player.Out.SendHousePayRentDialog("Housing07"); return; } // make sure the item dropped still exists InventoryItem orgitem = client.Player.Inventory.GetItem((eInventorySlot)slot); if (orgitem == null) { client.Player.Out.SendInventorySlotsUpdate(null); return; } if (orgitem.Id_nb == "house_removal_deed") { client.Out.SendInventorySlotsUpdate(null); // make sure player has owner permissions if (!house.HasOwnerPermissions(client.Player)) { ChatUtil.SendSystemMessage(client.Player, "You don't own this house!"); return; } client.Player.TempProperties.setProperty(DeedWeak, new WeakRef(orgitem)); client.Player.TempProperties.setProperty(TargetHouse, house); client.Player.Out.SendCustomDialog(LanguageMgr.GetTranslation(client.Account.Language, "WARNING: You are about to delete this house and all indoor and outdoor items attached to it!"), HouseRemovalDialog); return; } if (orgitem.Id_nb.Contains("cottage_deed") || orgitem.Id_nb.Contains("house_deed") || orgitem.Id_nb.Contains("villa_deed") || orgitem.Id_nb.Contains("mansion_deed")) { client.Out.SendInventorySlotsUpdate(null); // make sure player has owner permissions if (!house.HasOwnerPermissions(client.Player)) { ChatUtil.SendSystemMessage(client, "You may not change other peoples houses"); return; } client.Player.TempProperties.setProperty(DeedWeak, new WeakRef(orgitem)); client.Player.TempProperties.setProperty(TargetHouse, house); client.Player.Out.SendMessage("Warning:\n This will remove *all* items from your current house!", eChatType.CT_System, eChatLoc.CL_PopupWindow); client.Player.Out.SendCustomDialog("Are you sure you want to upgrade your House?", HouseUpgradeDialog); return; } if (orgitem.Name == "deed of guild transfer") { // player needs to be in a guild to xfer a house to a guild if (client.Player.Guild == null) { client.Out.SendInventorySlotsUpdate(new[] { slot }); ChatUtil.SendSystemMessage(client, "You must be a member of a guild to do that"); return; } // player needs to own the house to be able to xfer it if (!house.HasOwnerPermissions(client.Player)) { client.Out.SendInventorySlotsUpdate(new[] { slot }); ChatUtil.SendSystemMessage(client, "You do not own this house."); return; } // guild can't already have a house if (client.Player.Guild.GuildOwnsHouse) { client.Out.SendInventorySlotsUpdate(new[] { slot }); ChatUtil.SendSystemMessage(client, "Your Guild already owns a house."); return; } // player needs to be a GM in the guild to xfer his personal house to the guild if (!client.Player.Guild.HasRank(client.Player, Guild.eRank.Leader)) { client.Out.SendInventorySlotsUpdate(new[] { slot }); ChatUtil.SendSystemMessage(client, "You are not the leader of a guild."); return; } if (HouseMgr.HouseTransferToGuild(client.Player, house)) { // This will still take the item even if player answers NO to confirmation. // I'm fixing consignment, not housing, and frankly I'm sick of fixing stuff! :) - tolakram client.Player.Inventory.RemoveItem(orgitem); InventoryLogging.LogInventoryAction(client.Player, "(HOUSE;" + housenumber + ")", eInventoryActionType.Other, orgitem.Template, orgitem.Count); client.Player.Guild.UpdateGuildWindow(); } return; } if (house.CanChangeInterior(client.Player, DecorationPermissions.Remove)) { if (orgitem.Name == "interior banner removal") { house.IndoorGuildBanner = false; ChatUtil.SendSystemMessage(client.Player, "Scripts.Player.Housing.InteriorBannersRemoved", null); return; } if (orgitem.Name == "interior shield removal") { house.IndoorGuildShield = false; ChatUtil.SendSystemMessage(client.Player, "Scripts.Player.Housing.InteriorShieldsRemoved", null); return; } if (orgitem.Name == "carpet removal") { house.Rug1Color = 0; house.Rug2Color = 0; house.Rug3Color = 0; house.Rug4Color = 0; ChatUtil.SendSystemMessage(client.Player, "Scripts.Player.Housing.CarpetsRemoved", null); return; } } if (house.CanChangeExternalAppearance(client.Player)) { if (orgitem.Name == "exterior banner removal") { house.OutdoorGuildBanner = false; ChatUtil.SendSystemMessage(client.Player, "Scripts.Player.Housing.OutdoorBannersRemoved", null); return; } if (orgitem.Name == "exterior shield removal") { house.OutdoorGuildShield = false; ChatUtil.SendSystemMessage(client.Player, "Scripts.Player.Housing.OutdoorShieldsRemoved", null); return; } } int objType = orgitem.Object_Type; if (objType == 49) // Garden items { method = 1; } else if (orgitem.Id_nb == "housing_porch_deed" || orgitem.Id_nb == "housing_porch_remove_deed" || orgitem.Id_nb == "housing_consignment_deed") { method = 4; } else if (objType >= 59 && objType <= 64) // Outdoor Roof/Wall/Door/Porch/Wood/Shutter/awning Material item type { ChatUtil.SendSystemMessage(client.Player, "Scripts.Player.Housing.HouseUseMaterials", null); return; } else if (objType == 56 || objType == 52 || (objType >= 69 && objType <= 71)) // Indoor carpets 1-4 { ChatUtil.SendSystemMessage(client.Player, "Scripts.Player.Housing.HouseUseCarpets", null); return; } else if (objType == 57 || objType == 58 || // Exterior banner/shield objType == 66 || objType == 67) // Interior banner/shield { method = 6; } else if (objType == 53 || objType == 55 || objType == 68) { method = 5; } else if (objType == (int)eObjectType.HouseVault) { method = 7; } ChatUtil.SendDebugMessage(client, $"Place Item: method: {method}"); int pos; switch (method) { case 1: // GARDEN OBJECT { if (client.Player.InHouse) { client.Out.SendInventorySlotsUpdate(new[] { slot }); return; } // no permissions to add to the garden, return if (!house.CanChangeGarden(client.Player, DecorationPermissions.Add)) { client.Out.SendInventorySlotsUpdate(new[] { slot }); return; } // garden is already full, return if (house.OutdoorItems.Count >= Properties.MAX_OUTDOOR_HOUSE_ITEMS) { ChatUtil.SendSystemMessage(client, "Scripts.Player.Housing.GardenMaxObjects", null); client.Out.SendInventorySlotsUpdate(new[] { slot }); return; } // create an outdoor item to represent the item being placed var oitem = new OutdoorItem { BaseItem = GameServer.Database.FindObjectByKey <ItemTemplate>(orgitem.Id_nb), Model = orgitem.Model, Position = (byte)_position, Rotation = (byte)rotation }; // add item in db pos = GetFirstFreeSlot(house.OutdoorItems.Keys); DBHouseOutdoorItem odbitem = oitem.CreateDBOutdoorItem(housenumber); oitem.DatabaseItem = odbitem; GameServer.Database.AddObject(odbitem); // remove the item from the player's inventory client.Player.Inventory.RemoveItem(orgitem); InventoryLogging.LogInventoryAction(client.Player, $"(HOUSE;{housenumber})", eInventoryActionType.Other, orgitem.Template, orgitem.Count); // add item to outdooritems house.OutdoorItems.Add(pos, oitem); ChatUtil.SendSystemMessage(client, "Scripts.Player.Housing.GardenItemPlaced", Properties.MAX_OUTDOOR_HOUSE_ITEMS - house.OutdoorItems.Count); ChatUtil.SendSystemMessage(client, "Scripts.Player.Housing.GardenItemPlacedName", orgitem.Name); // update all nearby players foreach (GamePlayer player in WorldMgr.GetPlayersCloseToSpot(house.RegionID, house, WorldMgr.OBJ_UPDATE_DISTANCE)) { player.Out.SendGarden(house); } // save the house house.SaveIntoDatabase(); break; } case 2: // WALL OBJECT case 3: // FLOOR OBJECT { if (client.Player.InHouse == false) { client.Out.SendInventorySlotsUpdate(new[] { slot }); return; } // no permission to add to the interior, return if (!house.CanChangeInterior(client.Player, DecorationPermissions.Add)) { client.Out.SendInventorySlotsUpdate(new[] { slot }); return; } // not a wall object, return if (!IsSuitableForWall(orgitem) && method == 2) { ChatUtil.SendSystemMessage(client, "Scripts.Player.Housing.NotWallObject", null); client.Out.SendInventorySlotsUpdate(new[] { slot }); return; } // not a floor object, return if (objType != 51 && method == 3) { ChatUtil.SendSystemMessage(client, "Scripts.Player.Housing.NotFloorObject", null); client.Out.SendInventorySlotsUpdate(new[] { slot }); return; } // interior already has max items, return if (house.IndoorItems.Count >= GetMaxIndoorItemsForHouse(house.Model)) { ChatUtil.SendSystemMessage(client, "Scripts.Player.Housing.IndoorMaxItems", GetMaxIndoorItemsForHouse(house.Model)); client.Out.SendInventorySlotsUpdate(new[] { slot }); return; } // create an indoor item to represent the item being placed var iitem = new IndoorItem { Model = orgitem.Model, Color = orgitem.Color, X = xpos, Y = ypos, Size = orgitem.DPS_AF > 3 ? orgitem.DPS_AF : 100, // max size is 255 Position = _position, PlacementMode = method, BaseItem = null }; // figure out proper rotation for item int properRotation = client.Player.Heading / 10; properRotation = properRotation.Clamp(0, 360); if (method == 2 && IsSuitableForWall(orgitem)) { properRotation = 360; if (objType != 50) { client.Out.SendInventorySlotsUpdate(new[] { slot }); } } iitem.Rotation = properRotation; pos = GetFirstFreeSlot(house.IndoorItems.Keys); if (objType == 50 || objType == 51) { // its a housing item, so lets take it! client.Player.Inventory.RemoveItem(orgitem); InventoryLogging.LogInventoryAction(client.Player, $"(HOUSE;{housenumber})", eInventoryActionType.Other, orgitem.Template, orgitem.Count); // set right base item, so we can recreate it on take. if (orgitem.Id_nb.Contains("GuildBanner")) { iitem.BaseItem = orgitem.Template; iitem.Size = 50; // Banners have to be reduced in size } else { iitem.BaseItem = GameServer.Database.FindObjectByKey <ItemTemplate>(orgitem.Id_nb); } } DBHouseIndoorItem idbitem = iitem.CreateDBIndoorItem(housenumber); iitem.DatabaseItem = idbitem; GameServer.Database.AddObject(idbitem); house.IndoorItems.Add(pos, iitem); // let player know the item has been placed ChatUtil.SendSystemMessage(client, "Scripts.Player.Housing.IndoorItemPlaced", GetMaxIndoorItemsForHouse(house.Model) - house.IndoorItems.Count); switch (method) { case 2: ChatUtil.SendSystemMessage(client, "Scripts.Player.Housing.IndoorWallPlaced", orgitem.Name); break; case 3: ChatUtil.SendSystemMessage(client, "Scripts.Player.Housing.IndoorFloorPlaced", orgitem.Name); break; } // update furniture for all players in the house foreach (GamePlayer plr in house.GetAllPlayersInHouse()) { plr.Out.SendFurniture(house, pos); } break; } case 4: // PORCH { // no permission to add to the garden, return if (!house.CanChangeGarden(client.Player, DecorationPermissions.Add)) { client.Out.SendInventorySlotsUpdate(new[] { slot }); return; } switch (orgitem.Id_nb) { case "housing_porch_deed": // try and add the porch if (house.AddPorch()) { // remove the original item from the player's inventory client.Player.Inventory.RemoveItem(orgitem); InventoryLogging.LogInventoryAction(client.Player, $"(HOUSE;{housenumber})", eInventoryActionType.Other, orgitem.Template, orgitem.Count); } else { ChatUtil.SendSystemMessage(client, "Scripts.Player.Housing.PorchAlready", null); client.Out.SendInventorySlotsUpdate(new[] { slot }); } return; case "housing_porch_remove_deed": var consignmentMerchant = house.ConsignmentMerchant; if (consignmentMerchant != null && (consignmentMerchant.DBItems(client.Player).Count > 0 || consignmentMerchant.TotalMoney > 0)) { ChatUtil.SendSystemMessage(client, "All items and money must be removed from your consigmment merchant in order to remove the porch!"); client.Out.SendInventorySlotsUpdate(new[] { slot }); return; } // try and remove the porch if (house.RemovePorch()) { // remove the original item from the player's inventory client.Player.Inventory.RemoveItem(orgitem); InventoryLogging.LogInventoryAction(client.Player, $"(HOUSE;{housenumber})", eInventoryActionType.Other, orgitem.Template, orgitem.Count); } else { ChatUtil.SendSystemMessage(client, "Scripts.Player.Housing.PorchNone", null); client.Out.SendInventorySlotsUpdate(new[] { slot }); } return; case "housing_consignment_deed": { // make sure there is a porch for this consignment merchant! if (!house.Porch) { ChatUtil.SendSystemMessage(client, "Your House needs a Porch first."); client.Out.SendInventorySlotsUpdate(new[] { slot }); return; } // try and add a new consignment merchant if (house.AddConsignment(0)) { // remove the original item from the player's inventory client.Player.Inventory.RemoveItem(orgitem); InventoryLogging.LogInventoryAction(client.Player, $"(HOUSE;{housenumber})", eInventoryActionType.Other, orgitem.Template, orgitem.Count); } else { ChatUtil.SendSystemMessage(client, "You can not add a Consignment Merchant here."); client.Out.SendInventorySlotsUpdate(new[] { slot }); } return; } default: ChatUtil.SendSystemMessage(client, "Scripts.Player.Housing.PorchNotItem", null); client.Out.SendInventorySlotsUpdate(new[] { slot }); return; } } case 5: // HOOKPOINT { if (client.Player.InHouse == false) { client.Out.SendInventorySlotsUpdate(new[] { slot }); return; } // no permission to add to the interior, return if (!house.CanChangeInterior(client.Player, DecorationPermissions.Add)) { client.Out.SendInventorySlotsUpdate(new[] { slot }); return; } // don't allow non-hookpoint items to be dropped on hookpoints if (IsSuitableForHookpoint(orgitem) == false) { client.Out.SendInventorySlotsUpdate(new[] { slot }); return; } // if the hookpoint doesn't exist, prompt player to Log it in the database for us if (house.GetHookpointLocation((uint)_position) == null) { client.Out.SendInventorySlotsUpdate(new[] { slot }); if (client.Account.PrivLevel == (int)ePrivLevel.Admin) { if (client.Player.TempProperties.getProperty(HousingConstants.AllowAddHouseHookpoint, false)) { ChatUtil.SendSystemMessage(client, "Scripts.Player.Housing.HookPointID", +_position); ChatUtil.SendSystemMessage(client, "Scripts.Player.Housing.HookPointCloser", null); client.Player.Out.SendCustomDialog(LanguageMgr.GetTranslation(client.Account.Language, "Scripts.Player.Housing.HookPointLogLoc"), LogLocation); } else { ChatUtil.SendDebugMessage(client, "use '/house addhookpoints' to allow addition of new housing hookpoints."); } } } else if (house.GetHookpointLocation((uint)_position) != null) { var point = new DBHouseHookpointItem { HouseNumber = house.HouseNumber, ItemTemplateID = orgitem.Id_nb, HookpointID = (uint)_position }; // If we already have soemthing here, do not place more foreach (var hpitem in GameServer.Database.SelectObjects <DBHouseHookpointItem>("`HouseNumber` = @HouseNumber", new QueryParameter("@HouseNumber", house.HouseNumber))) { if (hpitem.HookpointID == point.HookpointID) { ChatUtil.SendSystemMessage(client, "Scripts.Player.Housing.HookPointAlready", null); client.Out.SendInventorySlotsUpdate(new[] { slot }); return; } } if (house.HousepointItems.ContainsKey(point.HookpointID) == false) { house.HousepointItems.Add(point.HookpointID, point); house.FillHookpoint((uint)_position, orgitem.Id_nb, client.Player.Heading, 0); } else { string error = $"Hookpoint already has item on attempt to attach {orgitem.Id_nb} to hookpoint {_position} for house {house.HouseNumber}!"; Log.ErrorFormat(error); client.Out.SendInventorySlotsUpdate(new[] { slot }); throw new Exception(error); } // add the item to the database GameServer.Database.AddObject(point); // remove the original item from the player's inventory client.Player.Inventory.RemoveItem(orgitem); InventoryLogging.LogInventoryAction(client.Player, $"(HOUSE;{housenumber})", eInventoryActionType.Other, orgitem.Template, orgitem.Count); ChatUtil.SendSystemMessage(client, "Scripts.Player.Housing.HookPointAdded", null); // save the house house.SaveIntoDatabase(); } else { ChatUtil.SendSystemMessage(client, "Scripts.Player.Housing.HookPointNot", null); client.Out.SendInventorySlotsUpdate(new[] { slot }); } // broadcast updates house.SendUpdate(); break; } case 6: { // no permission to change external appearance, return if (!house.CanChangeExternalAppearance(client.Player)) { client.Out.SendInventorySlotsUpdate(new[] { slot }); return; } if (objType == 57) // We have outdoor banner { house.OutdoorGuildBanner = true; ChatUtil.SendSystemMessage(client, "Scripts.Player.Housing.OutdoorBannersAdded", null); client.Player.Inventory.RemoveItem(orgitem); InventoryLogging.LogInventoryAction(client.Player, $"(HOUSE;{housenumber})", eInventoryActionType.Other, orgitem.Template, orgitem.Count); } else if (objType == 58) // We have outdoor shield { house.OutdoorGuildShield = true; ChatUtil.SendSystemMessage(client, "Scripts.Player.Housing.OutdoorShieldsAdded", null); client.Player.Inventory.RemoveItem(orgitem); InventoryLogging.LogInventoryAction(client.Player, $"(HOUSE;{housenumber})", eInventoryActionType.Other, orgitem.Template, orgitem.Count); } else if (objType == 66) // We have indoor banner { house.IndoorGuildBanner = true; ChatUtil.SendSystemMessage(client, "Scripts.Player.Housing.InteriorBannersAdded", null); client.Player.Inventory.RemoveItem(orgitem); InventoryLogging.LogInventoryAction(client.Player, $"(HOUSE;{housenumber})", eInventoryActionType.Other, orgitem.Template, orgitem.Count); } else if (objType == 67) // We have indoor shield { house.IndoorGuildShield = true; ChatUtil.SendSystemMessage(client, "Scripts.Player.Housing.InteriorShieldsAdded", null); client.Player.Inventory.RemoveItem(orgitem); InventoryLogging.LogInventoryAction(client.Player, $"(HOUSE;{housenumber})", eInventoryActionType.Other, orgitem.Template, orgitem.Count); } else { ChatUtil.SendSystemMessage(client, "Scripts.Player.Housing.BadShieldBanner", null); client.Out.SendInventorySlotsUpdate(new[] { slot }); } // save the house and broadcast updates house.SaveIntoDatabase(); house.SendUpdate(); break; } case 7: // House vault. { if (client.Player.InHouse == false) { client.Out.SendInventorySlotsUpdate(new[] { slot }); return; } // make sure the hookpoint position is valid if (_position > HousingConstants.MaxHookpointLocations) { ChatUtil.SendSystemMessage(client, "This hookpoint position is unknown, error logged."); Log.Error($"HOUSING: {client.Player.Name} working with invalid position {_position} in house {house.HouseNumber} model {house.Model}"); client.Out.SendInventorySlotsUpdate(new[] { slot }); return; } // if hookpoint doesn't exist, prompt player to Log it in the database for us if (house.GetHookpointLocation((uint)_position) == null) { client.Out.SendInventorySlotsUpdate(new[] { slot }); if (client.Account.PrivLevel == (int)ePrivLevel.Admin) { if (client.Player.TempProperties.getProperty(HousingConstants.AllowAddHouseHookpoint, false)) { ChatUtil.SendSystemMessage(client, "Scripts.Player.Housing.HookPointID", +_position); ChatUtil.SendSystemMessage(client, "Scripts.Player.Housing.HookPointCloser", null); client.Player.Out.SendCustomDialog(LanguageMgr.GetTranslation(client.Account.Language, "Scripts.Player.Housing.HookPointLogLoc"), LogLocation); } else { ChatUtil.SendDebugMessage(client, "use '/house addhookpoints' to allow addition of new housing hookpoints."); } } return; } // make sure we have space to add another vult int vaultIndex = house.GetFreeVaultNumber(); if (vaultIndex < 0) { client.Player.Out.SendMessage("You can't add any more vaults to this house!", eChatType.CT_System, eChatLoc.CL_SystemWindow); client.Out.SendInventorySlotsUpdate(new[] { slot }); return; } // If we already have soemthing here, do not place more foreach (var hpitem in GameServer.Database.SelectObjects <DBHouseHookpointItem>("`HouseNumber` = @HouseNumber", new QueryParameter("@HouseNumber", house.HouseNumber))) { if (hpitem.HookpointID == _position) { ChatUtil.SendSystemMessage(client, "Scripts.Player.Housing.HookPointAlready", null); client.Out.SendInventorySlotsUpdate(new[] { slot }); return; } } // create the new vault and attach it to the house var houseVault = new GameHouseVault(orgitem.Template, vaultIndex); houseVault.Attach(house, (uint)_position, (ushort)((client.Player.Heading + 2048) % 4096)); // remove the original item from the player's inventory client.Player.Inventory.RemoveItem(orgitem); InventoryLogging.LogInventoryAction(client.Player, $"(HOUSE;{housenumber})", eInventoryActionType.Other, orgitem.Template, orgitem.Count); // save the house and broadcast uodates house.SaveIntoDatabase(); house.SendUpdate(); return; } default: { ChatUtil.SendDebugMessage(client, "Place Item: Unknown method, do nothing."); client.Out.SendInventorySlotsUpdate(null); break; } } } catch (Exception ex) { Log.Error("HousingPlaceItemHandler", ex); client.Out.SendMessage("Error processing housing action; the error has been logged!", eChatType.CT_Staff, eChatLoc.CL_SystemWindow); client.Out.SendInventorySlotsUpdate(null); } }
public void HandlePacket(GameClient client, GSPacketIn packet) { var player = client.Player; ushort jumpSpotId; if (client.Version < GameClient.eClientVersion.Version1126) { jumpSpotId = packet.ReadShort(); } else { jumpSpotId = packet.ReadShortLowEndian(); } eRealm targetRealm = player.Realm; if (player.CurrentRegion.Expansion == (int)eClientExpansion.TrialsOfAtlantis && player.CurrentZone.Realm != eRealm.None) { // if we are in TrialsOfAtlantis then base the target jump on the current region realm instead of the players realm // this is only used if zone table has the proper realms defined, otherwise it reverts to old behavior - Tolakram targetRealm = player.CurrentZone.Realm; } var filterRealm = DB.Column(nameof(ZonePoint.Realm)).IsEqualTo((byte)targetRealm).Or(DB.Column(nameof(ZonePoint.Realm)).IsEqualTo(0)).Or(DB.Column(nameof(ZonePoint.Realm)).IsNull()); var zonePoint = DOLDB <ZonePoint> .SelectObject(DB.Column(nameof(ZonePoint.Id)).IsEqualTo(jumpSpotId).And(filterRealm)); if (zonePoint == null || zonePoint.TargetRegion == 0) { ChatUtil.SendDebugMessage(client, $"Invalid Jump (ZonePoint table): [{jumpSpotId}]{((zonePoint == null) ? ". Entry missing!" : ". TargetRegion is 0!")}"); zonePoint = new ZonePoint(); zonePoint.Id = jumpSpotId; string zonePointLocation = $"Region {player.CurrentRegionID} and coordinates ({player.X},{player.Y},{player.Z})"; Log.Error($"ZonePoint {jumpSpotId} at {zonePointLocation} on client {client.Version} missing. Either ZonePoint missing or RegionChangeRequestHandler needs to be updated."); } if (client.Account.PrivLevel > 1) { client.Out.SendMessage($"JumpSpotID = {jumpSpotId}", eChatType.CT_System, eChatLoc.CL_SystemWindow); client.Out.SendMessage($"ZonePoint Target: Region = {zonePoint.TargetRegion}, ClassType = \'{zonePoint.ClassType}\'", eChatType.CT_System, eChatLoc.CL_SystemWindow); } //Dinberg: Fix - some jump points are handled code side, such as instances. //As such, region MAY be zero in the database, so this causes an issue. if (zonePoint.TargetRegion != 0) { Region reg = WorldMgr.GetRegion(zonePoint.TargetRegion); if (reg != null) { // check for target region disabled if player is in a standard region // otherwise the custom region should handle OnZonePoint for this check if (player.CurrentRegion.IsCustom == false && reg.IsDisabled) { if ((player.Mission is TaskDungeonMission && (player.Mission as TaskDungeonMission).TaskRegion.Skin == reg.Skin) == false) { client.Out.SendMessage("This region has been disabled!", eChatType.CT_System, eChatLoc.CL_SystemWindow); if (client.Account.PrivLevel == 1) { return; } } } } } // Allow the region to either deny exit or handle the zonepoint in a custom way if (player.CurrentRegion.OnZonePoint(player, zonePoint) == false) { return; } //check caps for battleground Battleground bg = GameServer.KeepManager.GetBattleground(zonePoint.TargetRegion); if (bg != null) { if (player.Level < bg.MinLevel && player.Level > bg.MaxLevel && player.RealmLevel >= bg.MaxRealmLevel) { return; } } IJumpPointHandler customHandler = null; if (string.IsNullOrEmpty(zonePoint.ClassType) == false) { customHandler = (IJumpPointHandler)m_customJumpPointHandlers[zonePoint.ClassType]; // check for db change to update cached handler if (customHandler != null && customHandler.GetType().FullName != zonePoint.ClassType) { customHandler = null; } if (customHandler == null) { //Dinberg - Instances need to use a special handler. This is because some instances will result //in duplicated zonepoints, such as if Tir Na Nog were to be instanced for a quest. string type = player.CurrentRegion.IsInstance ? "DOL.GS.ServerRules.InstanceDoorJumpPoint" : zonePoint.ClassType; Type t = ScriptMgr.GetType(type); if (t == null) { Log.ErrorFormat("jump point {0}: class {1} not found!", zonePoint.Id, zonePoint.ClassType); } else if (!typeof(IJumpPointHandler).IsAssignableFrom(t)) { Log.ErrorFormat("jump point {0}: class {1} must implement IJumpPointHandler interface!", zonePoint.Id, zonePoint.ClassType); } else { try { customHandler = (IJumpPointHandler)Activator.CreateInstance(t); } catch (Exception e) { customHandler = null; Log.Error( string.Format("jump point {0}: error creating a new instance of jump point handler {1}", zonePoint.Id, zonePoint.ClassType), e); } } } if (customHandler != null) { m_customJumpPointHandlers[zonePoint.ClassType] = customHandler; } } new RegionChangeRequestHandler(player, zonePoint, customHandler).Start(1); }