Beispiel #1
0
        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);
        }
Beispiel #2
0
        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);
        }
Beispiel #4
0
        /// <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;
            }
        }
Beispiel #5
0
        //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();
                    }
                }
            }
        }
Beispiel #6
0
        //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();
                    }
                }
            }
        }
Beispiel #7
0
        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);
            }
        }
Beispiel #8
0
        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);
        }