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); } }