private static bool SharedHasObstacle( ICharacter character, IStaticWorldObject forStructureRelocation, Vector2D position) { if (PveSystem.SharedIsPve(false)) { return(false); } var characterCenter = character.Position + character.PhysicsBody.CenterOffset; return(TestHasObstacle(position)); // local method for testing if there is an obstacle from current to the specified position bool TestHasObstacle(Vector2D toPosition) { using var obstaclesInTheWay = character.PhysicsBody.PhysicsSpace.TestLine( characterCenter, toPosition, CollisionGroup.Default, sendDebugEvent: false); foreach (var test in obstaclesInTheWay.AsList()) { var testPhysicsBody = test.PhysicsBody; if (testPhysicsBody.AssociatedProtoTile is not null) { // obstacle tile on the way return(true); } var testWorldObject = testPhysicsBody.AssociatedWorldObject; if (testWorldObject is null || ReferenceEquals(testWorldObject, character) || ReferenceEquals(testWorldObject, forStructureRelocation)) { // not an obstacle - it's the character or world object itself continue; } switch (testWorldObject.ProtoWorldObject) { case IProtoObjectDeposit: // allow deposits case ObjectWallDestroyed: // allow destroyed walls continue; } // obstacle object on the way return(true); } // no obstacles return(false); } }
protected override void PrepareTileRequirements(ConstructionTileRequirements tileRequirements) { base.PrepareTileRequirements(tileRequirements); // disallow placing mining bombs on the floor on the PvE servers tileRequirements.Add( new ConstructionTileRequirements.Validator( ConstructionTileRequirements.ErrorNoFreeSpace, c => !PveSystem.SharedIsPve(clientLogErrorIfDataIsNotYetAvailable: false) || c.Tile.StaticObjects.All( o => o.ProtoStaticWorldObject.Kind != StaticObjectKind.Floor))); }
public override bool SharedCanInteract(ICharacter character, IStaticWorldObject worldObject, bool writeToLog) { if (!base.SharedCanInteract(character, worldObject, writeToLog)) { return(false); } var ownerName = GetPublicState(worldObject).OwnerName; if (ownerName == character.Name) { return(true); } if (PveSystem.SharedIsPve(false)) { if (IsClient && PartySystem.ClientIsPartyMember(ownerName) || (IsServer && PartySystem.ServerIsSameParty(Server.Characters.GetPlayerCharacter(ownerName), character))) { // in PvE party members can pickup items of their party members } else { // other players in PvE cannot pickup player's loot if (writeToLog && IsClient) { PveSystem.ClientShowNotificationActionForbidden(); } return(false); } } if (NewbieProtectionSystem.SharedIsNewbie(character)) { // newbie cannot pickup other players' loot if (writeToLog) { NewbieProtectionSystem.SharedShowNewbieCannotDamageOtherPlayersOrLootBags(character, isLootBag: true); } return(false); } // non-newbie character can pickup players' loot // please note this validation has an override for derived ObjectPlayerLootContainerProtected return(true); }
public double Get(TechTier tier, bool isSpecialized) { if (PveSystem.SharedIsPve(false)) { return(0); } var tierIndex = (int)tier - (int)TechConstants.PvPTimeGateStartsFromTier; if (tierIndex < 0) { return(0); } var index = 2 * tierIndex + (isSpecialized ? 1 : 0); return(this.TimeGates[index]); }
public virtual bool SharedCanInteract(ICharacter character, TWorldObject worldObject, bool writeToLog) { if (!this.IsInteractableObject) { return(false); } if (character.GetPublicState <ICharacterPublicState>().IsDead || IsServer && !character.ServerIsOnline) { return(false); } if (worldObject is IStaticWorldObject staticWorldObject) { if (PveSystem.SharedIsPve(clientLogErrorIfDataIsNotYetAvailable: false)) { if (!PveSystem.SharedValidateInteractionIsNotForbidden(character, staticWorldObject, writeToLog)) { // action forbidden by PvE system return(false); } } else // PvP servers have newbie protection system { if (!NewbieProtectionSystem.SharedValidateInteractionIsNotForbidden( character, staticWorldObject, writeToLog)) { // action forbidden by newbie protection system return(false); } } } return(this.SharedIsInsideCharacterInteractionArea(character, worldObject, writeToLog)); }
protected override double SharedCalculateDamageByWeapon( WeaponFinalCache weaponCache, double damagePreMultiplier, IDynamicWorldObject targetObject, out double obstacleBlockDamageCoef) { if (PveSystem.SharedIsPve(false) && (weaponCache.Character is null || !weaponCache.Character.IsNpc)) { // no PvP damage in PvE (only creature damage is allowed) obstacleBlockDamageCoef = 0; return(0); } return(base.SharedCalculateDamageByWeapon(weaponCache, damagePreMultiplier, targetObject, out obstacleBlockDamageCoef)); }
private static double SharedGetSpeedMultiplier(IStaticWorldObject objectDeposit) { return(GetDepositExtractionRateMultiplier() * StructureConstants.DepositsExtractionSpeedMultiplier); double GetDepositExtractionRateMultiplier() { if (PveSystem.SharedIsPve(clientLogErrorIfDataIsNotYetAvailable: false)) { return(ExtractorPvE); } // extractor in PvP if (objectDeposit is null) { return(ExtractorPvpWithoutDeposit); } var protoObjectDeposit = (IProtoObjectDeposit)objectDeposit.ProtoStaticWorldObject; return(ExtractorPvpWithDeposit); } }
public static bool SharedIsAllowInteraction( ICharacter character, IStaticWorldObject worldObject, bool showClientNotification) { if (!SharedIsEnabled) { return(true); } if (character is null || !PveSystem.SharedIsPve(clientLogErrorIfDataIsNotYetAvailable: false)) { return(true); } var worldObjectPublicState = worldObject.AbstractPublicState as IWorldObjectPublicStateWithClaim; if (worldObjectPublicState?.WorldObjectClaim is null || WorldObjectClaim.SharedIsClaimedForPlayer(worldObjectPublicState.WorldObjectClaim, character)) { return(true); } if (IsClient && showClientNotification) { NotificationSystem.ClientShowNotification( CoreStrings.WorldObjectClaim_Title, CoreStrings.WorldObjectClaim_Description + "[br]" + CoreStrings.WorldObjectClaim_Description2, NotificationColor.Bad, icon: TextureResourceClaimedObject); } return(false); }
public static void ClientStartRelocation(IStaticWorldObject objectStructure) { var protoStructure = objectStructure.ProtoStaticWorldObject; var character = Client.Characters.CurrentPlayerCharacter; if (IsInObjectPlacementMode || ConstructionPlacementSystem.IsInObjectPlacementMode) { // already relocating/placing something return; } if (!SharedIsRelocatable(objectStructure)) { return; } if (!CreativeModeSystem.SharedIsInCreativeMode(character) && !LandClaimSystem.SharedIsOwnedLand(objectStructure.TilePosition, character, requireFactionPermission: true, out var hasNoFactionPermission, out _)) { // the building location or destination is in an area that is not owned by the player SharedShowCannotRelocateNotification( character, protoStructure, hasNoFactionPermission); return; } var isPvEorWithinInteractionArea = PveSystem.SharedIsPve(false) || protoStructure.SharedIsInsideCharacterInteractionArea( Api.Client.Characters.CurrentPlayerCharacter, objectStructure, writeToLog: false); if (!isPvEorWithinInteractionArea) { CannotInteractMessageDisplay.ClientOnCannotInteract( character, CoreStrings.Notification_TooFar, isOutOfRange: true); return; } if (LandClaimSystem.SharedIsUnderRaidBlock(character, objectStructure)) { // the building is in an area under the raid ConstructionSystem.SharedShowCannotBuildNotification( character, LandClaimSystem.ErrorRaidBlockActionRestricted_Message, protoStructure); return; } if (LandClaimShieldProtectionSystem.SharedIsUnderShieldProtection(objectStructure)) { // the building is in an area under shield protection LandClaimShieldProtectionSystem.SharedSendNotificationActionForbiddenUnderShieldProtection( character); return; } ClientDisableConstructionRelocation(); var sceneObject = Client.Scene.CreateSceneObject("StructureRelocationHelper"); componentObjectPlacementHelper = sceneObject.AddComponent <ClientComponentObjectPlacementHelper>(); componentRelocationHelper = sceneObject.AddComponent <ClientComponentObjectRelocationHelper>(); componentObjectPlacementHelper .Setup(protoStructure, isCancelable: true, isRepeatCallbackIfHeld: false, isDrawConstructionGrid: true, isBlockingInput: true, validateCanPlaceCallback: ClientValidateCanRelocate, placeSelectedCallback: ClientConstructionPlaceSelectedCallback, delayRemainsSeconds: 0.1); componentObjectPlacementHelper.HideBlueprintOnOverlapWithTheSameObject = false; componentRelocationHelper.Setup(objectStructure); void ClientValidateCanRelocate( Vector2Ushort tilePosition, bool logErrors, out string errorMessage, out bool canPlace, out bool isTooFar) { if (tilePosition == objectStructure.TilePosition) { canPlace = true; isTooFar = false; errorMessage = null; return; } if (!SharedCheckTileRequirementsForRelocation(character, objectStructure, tilePosition, out errorMessage, logErrors: logErrors)) { // time requirements are not valid canPlace = false; isTooFar = false; return; } if (!SharedValidateCanCharacterRelocateStructure(character, objectStructure, tilePosition, out errorMessage, logErrors: logErrors)) { canPlace = true; isTooFar = true; return; } if (SharedHasObstacle( character, objectStructure, tilePosition.ToVector2D() + protoStructure.Layout.Center)) { if (logErrors) { CannotInteractMessageDisplay.ClientOnCannotInteract( character, CoreStrings.Notification_ObstaclesOnTheWay, isOutOfRange: true); } errorMessage = CoreStrings.Notification_ObstaclesOnTheWay; canPlace = true; isTooFar = true; return; } canPlace = true; isTooFar = false; } void ClientConstructionPlaceSelectedCallback(Vector2Ushort tilePosition) { if (SharedHasObstacle( character, objectStructure, tilePosition.ToVector2D() + protoStructure.Layout.Center)) { CannotInteractMessageDisplay.ClientOnCannotInteract( character, CoreStrings.Notification_ObstaclesOnTheWay, isOutOfRange: true); return; } ClientTimersSystem.AddAction(0.1, ClientDisableConstructionRelocation); if (tilePosition != objectStructure.TilePosition) { Instance.CallServer(_ => _.ServerRemote_RelocateStructure(objectStructure, tilePosition)); } } }
public static bool SharedValidateCanCharacterRelocateStructure( ICharacter character, IStaticWorldObject objectStructure, Vector2Ushort toPosition, out string errorMessage, bool logErrors) { if (!SharedIsRelocatable(objectStructure)) { errorMessage = null; return(false); } if (!SharedCheckTileRequirementsForRelocation(character, objectStructure, toPosition, out errorMessage, logErrors)) { return(false); } if (!(objectStructure.ProtoGameObject is IProtoObjectStructure protoStructure)) { return(false); } var maxRelocationDistance = PveSystem.SharedIsPve(true) ? MaxRelocationDistancePvE : MaxRelocationDistancePvP; if (objectStructure.TilePosition.TileSqrDistanceTo(toPosition) > maxRelocationDistance * maxRelocationDistance) { if (logErrors) { ConstructionSystem.SharedShowCannotPlaceNotification( character, CoreStrings.Notification_TooFar, protoStructure); } errorMessage = CoreStrings.Notification_TooFar; return(false); } var itemInHands = character.SharedGetPlayerSelectedHotbarItem(); if (!(itemInHands.ProtoGameObject is IProtoItemToolToolbox)) { return(false); } if (CreativeModeSystem.SharedIsInCreativeMode(character)) { errorMessage = null; return(true); } if (!LandClaimSystem.SharedIsOwnedLand(objectStructure.TilePosition, character, requireFactionPermission: true, out var hasNoFactionPermission, ownedArea: out _) || !IsOwnedLand(toPosition, out hasNoFactionPermission)) { errorMessage = string.Format(CoreStrings.Faction_Permission_Required_Format, CoreStrings.Faction_Permission_LandClaimManagement_Title); // the building location or destination is in an area that is not owned by the player if (logErrors) { SharedShowCannotRelocateNotification( character, protoStructure, hasNoFactionPermission); } return(false); } if (LandClaimSystem.SharedIsUnderRaidBlock(character, objectStructure)) { // the building is in an area under the raid errorMessage = LandClaimSystem.ErrorRaidBlockActionRestricted_Message; if (logErrors) { ConstructionSystem.SharedShowCannotPlaceNotification( character, LandClaimSystem.ErrorRaidBlockActionRestricted_Message, protoStructure); } return(false); } if (LandClaimShieldProtectionSystem.SharedIsUnderShieldProtection(objectStructure)) { // the building is in an area under shield protection errorMessage = CoreStrings.ShieldProtection_ActionRestrictedBaseUnderShieldProtection; if (logErrors) { LandClaimShieldProtectionSystem.SharedSendNotificationActionForbiddenUnderShieldProtection( character); } return(false); } errorMessage = null; return(true); bool IsOwnedLand( Vector2Ushort startTilePosition, out bool hasNoFactionPermission) { var worldObjectLayoutTileOffsets = objectStructure.ProtoStaticWorldObject.Layout.TileOffsets; foreach (var tileOffset in worldObjectLayoutTileOffsets) { if (!LandClaimSystem.SharedIsOwnedLand(startTilePosition.AddAndClamp(tileOffset), character, requireFactionPermission: true, out hasNoFactionPermission, out _)) { return(false); } } hasNoFactionPermission = false; return(true); } }
public virtual bool SharedCanInteract(ICharacter character, TWorldObject worldObject, bool writeToLog) { if (!this.IsInteractableObject) { return(false); } try { this.VerifyGameObject(worldObject); } catch (Exception ex) { Logger.Warning($"Interaction check failed: {ex.GetType().FullName}: {ex.Message}"); return(false); } if (character.GetPublicState <ICharacterPublicState>().IsDead || IsServer && !character.ServerIsOnline || ((IsServer || character.IsCurrentClientCharacter) && PlayerCharacter.GetPrivateState(character).IsDespawned)) { if (writeToLog) { Logger.Warning( $"Character cannot interact with {worldObject} - character is offline/despawned/dead.", character); } return(false); } if (worldObject is IStaticWorldObject staticWorldObject) { if (PveSystem.SharedIsPve(clientLogErrorIfDataIsNotYetAvailable: false)) { if (!PveSystem.SharedValidateInteractionIsNotForbidden(character, staticWorldObject, writeToLog)) { // action forbidden by PvE system return(false); } } else // PvP servers have newbie protection system { if (!NewbieProtectionSystem.SharedValidateInteractionIsNotForbidden( character, staticWorldObject, writeToLog)) { // action forbidden by newbie protection system return(false); } } } return(this.SharedIsInsideCharacterInteractionArea(character, worldObject, writeToLog)); }
private static void SharedRebuildAllNodes() { if (Api.IsClient && !PveSystem.ClientIsPveFlagReceived) { AvailableTechGroups = new TechGroup[0]; return; } var isPvE = PveSystem.SharedIsPve(false); var allTechGroups = Api.FindProtoEntities <TechGroup>(); foreach (var techGroup in allTechGroups) { SetupTimeGate(techGroup); techGroup.Nodes = techGroup.IsAvailable ? (IReadOnlyList <TechNode>)LazyAllNodesWithoutFiltering .Value .Where(n => n.Group == techGroup && n.IsAvailable) .OrderBy(n => n.HierarchyLevel) .ThenBy(n => n.Order) .ThenBy(n => n.ShortId) .ToList() : new TechNode[0]; var rootNodes = new List <TechNode>(); foreach (var node in techGroup.Nodes) { node.SharedResetCachedLearningPointsPrice(); if (node.IsRootNode) { rootNodes.Add(node); } } techGroup.RootNodes = rootNodes; var requirements = new Requirements(); techGroup.PrepareTechGroup(requirements); if (techGroup.LearningPointsPrice > 0) { requirements.Insert(0, new TechGroupRequirementLearningPoints(techGroup.LearningPointsPrice)); } if (!PveSystem.SharedIsPve(clientLogErrorIfDataIsNotYetAvailable: false) && techGroup.TimeGatePvP > 0) { requirements.Add(new TechGroupRequirementTimeGate(techGroup.TimeGatePvP)); } techGroup.GroupRequirements = requirements; Api.SafeInvoke(techGroup.NodesChanged); } AvailableTechGroups = allTechGroups.Where(t => t.IsAvailable).ToArray(); Api.SafeInvoke(AvailableTechGroupsChanged); void SetupTimeGate(TechGroup techGroup) { if (isPvE) { techGroup.TimeGatePvP = 0; return; } if (techGroup.IsPrimary) { techGroup.TimeGatePvP = techGroup.Tier switch { TechTier.Tier3 => TechConstants.PvpTechTimeGameTier3Basic, TechTier.Tier4 => TechConstants.PvpTechTimeGameTier4Basic, TechTier.Tier5 => TechConstants.PvpTechTimeGameTier5Basic, _ => 0 }; } else { techGroup.TimeGatePvP = techGroup.Tier switch { TechTier.Tier3 => TechConstants.PvpTechTimeGameTier3Specialized, TechTier.Tier4 => TechConstants.PvpTechTimeGameTier4Specialized, TechTier.Tier5 => TechConstants.PvpTechTimeGameTier5Specialized, _ => 0 }; } } }