using System; using System.Numerics; using log4net; using ACE.Entity; using ACE.Entity.Enum; using ACE.Entity.Enum.Properties; using ACE.Entity.Models; using ACE.Server.Entity; using ACE.Server.Network.GameEvent.Events; namespace ACE.Server.WorldObjects { public sealed class HousePortal : Portal { private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); public House House => ParentLink as House; /// /// A new biota be created taking all of its values from weenie. /// public HousePortal(Weenie weenie, ObjectGuid guid) : base(weenie, guid) { SetEphemeralValues(); } /// /// Restore a WorldObject from the database. /// public HousePortal(Biota biota) : base(biota) { SetEphemeralValues(); } public override void SetLinkProperties(WorldObject wo) { try { if (House == null) { log.Warn($"[HOUSE] HousePortal.SetLinkProperties({(wo != null ? $"{wo.Name}:0x{wo.Guid}:{wo.WeenieClassId}" : "null")}): House is null for HousePortal 0x{Guid} at {Location.ToLOCString()}"); return; } if (wo == null) { log.Warn($"[HOUSE] HousePortal.SetLinkProperties(null): WorldObject is null for HousePortal 0x{Guid} at {Location.ToLOCString()} | {(House != null ? $"House = {House.Name}:0x{House.Guid}:{House.WeenieClassId}" : "House is null")}"); return; } // get properties from parent? wo.HouseId = House.HouseId; wo.HouseOwner = House.HouseOwner; wo.HouseInstance = House.HouseInstance; if (wo.IsLinkSpot) { var housePortals = House.GetHousePortals(); if (housePortals.Count == 0) { Console.WriteLine($"{Name}.SetLinkProperties({wo.Name}): found LinkSpot, but empty HousePortals"); return; } var i = housePortals[0]; if (i.ObjCellId == Location.Cell) { if (housePortals.Count > 1) i = housePortals[1]; else { // there are some houses that for some reason, don't have return locations, so we'll fake the entry with a reference to the root house portal location mimicking other database entries. i = new Database.Models.World.HousePortal { ObjCellId = House.RootHouse.HousePortal.Location.Cell, OriginX = House.RootHouse.HousePortal.Location.PositionX, OriginY = House.RootHouse.HousePortal.Location.PositionY, OriginZ = House.RootHouse.HousePortal.Location.PositionZ, AnglesX = House.RootHouse.HousePortal.Location.RotationX, AnglesY = House.RootHouse.HousePortal.Location.RotationY, AnglesZ = House.RootHouse.HousePortal.Location.RotationZ, AnglesW = House.RootHouse.HousePortal.Location.RotationW }; } } var destination = new Position(i.ObjCellId, new Vector3(i.OriginX, i.OriginY, i.OriginZ), new Quaternion(i.AnglesX, i.AnglesY, i.AnglesZ, i.AnglesW)); wo.SetPosition(PositionType.Destination, destination); // set portal destination directly? SetPosition(PositionType.Destination, destination); } } catch (Exception ex) { log.Error($"[HOUSE] HousePortal.SetLinkProperties({(wo != null ? $"{wo.Name}:0x{wo.Guid}:{wo.WeenieClassId}" : "null")}): {(ParentLink != null ? $"ParentLink = {ParentLink.Name}:0x{ParentLink.Guid}:{ParentLink.WeenieClassId}" : "ParentLink is null")} {(House != null ? $"House = {House.Name}:0x{House.Guid}:{House.WeenieClassId}" : "House is null")} for HousePortal 0x{Guid} at {Location.ToLOCString()}\n Exception: {ex}"); } } public override ActivationResult CheckUseRequirements(WorldObject activator) { var rootHouse = House?.RootHouse; if (activator == null || rootHouse == null) { log.Warn($"HousePortal.CheckUseRequirements: 0x{Guid} - {Location.ToLOCString()}"); log.Warn($"HousePortal.CheckUseRequirements: activator is null - {activator == null} | House is null - {House == null} | RootHouse is null - {rootHouse == null}"); return new ActivationResult(false); } if (!(activator is Player player)) return new ActivationResult(false); if (player.IsOlthoiPlayer) return new ActivationResult(new GameEventWeenieError(player.Session, WeenieError.OlthoiMayNotUsePortal)); if (player.CurrentLandblock.IsDungeon && Destination.LandblockId != player.CurrentLandblock.Id) return new ActivationResult(true); // allow escape to overworld always if (player.IgnorePortalRestrictions) return new ActivationResult(true); var houseOwner = rootHouse.HouseOwner; if (houseOwner == null) //return new ActivationResult(new GameEventWeenieError(player.Session, WeenieError.YouMustBeHouseGuestToUsePortal)); return new ActivationResult(true); if (rootHouse.OpenToEveryone) return new ActivationResult(true); if (!rootHouse.HasPermission(player)) return new ActivationResult(new GameEventWeenieError(player.Session, WeenieError.YouMustBeHouseGuestToUsePortal)); return new ActivationResult(true); } /// /// House Portals are on Use activated, rather than collision based activation /// The actual portal process is wrapped to the base portal class ActOnUse, after ACL check are performed /// /// public override void ActOnUse(WorldObject worldObject) { // if house portal in dungeon, // set destination to outdoor house slumlord if (CurrentLandblock != null && CurrentLandblock.IsDungeon && Destination.LandblockId == CurrentLandblock.Id) SetPosition(PositionType.Destination, new Position(House.RootHouse.SlumLord.Location)); base.ActOnUse(worldObject); } } }