/// <summary> /// Checks if the position is blocked by anything that would prevent construction or anchoring. /// If blocked, optionally messages the performer telling them what's in the way. /// Valid on server only. /// </summary> /// <param name="performer">player performing trying to perform the action, will message if </param> /// <param name="anchoredObject">object being anchored, null if constructing a new object </param> /// <param name="worldPosition">world position the construction is attempted on </param> /// <param name="allowed">If defined, will be used to check each other registertile at the position. It should return /// true if this object is allowed to be built / anchored on top of the given register tile, otherwise false. /// If unspecified, all non-floor registertiles will be considered as blockers at the indicated position</param> public static bool IsConstructionBlocked(GameObject performer, GameObject anchoredObject, Vector2Int worldPosition, Func <RegisterTile, bool> allowed = null, bool messagePerformer = true) { var floorLayer = LayerMask.NameToLayer("Floor"); var wallmountLayer = LayerMask.NameToLayer("WallMounts"); if (allowed == null) { allowed = (rt) => false; } var blocker = MatrixManager.GetAt <RegisterTile>(worldPosition.To3Int(), true) //ignore the object itself (if anchoring) .Where(rt => rt.gameObject != anchoredObject) //ignore performer .Where(rt => rt.gameObject != performer) //ignore stuff in floor and wallmounts .Where(rt => rt.gameObject.layer != floorLayer && rt.gameObject.layer != wallmountLayer) .FirstOrDefault(rt => !allowed.Invoke(rt)); if (blocker != null) { //cannot build if there's anything in the way (other than the builder). if (messagePerformer) { Chat.AddExamineMsg(performer, $"{blocker.gameObject.ExpensiveName()} is in the way."); } return(true); } return(false); }
protected override void Gib() { EffectsFactory.BloodSplat(transform.position, BloodSplatSize.large, bloodColor); //drop clothes, gib... but don't destroy actual player, a piece should remain //drop everything foreach (var slot in itemStorage.GetItemSlots()) { Inventory.ServerDrop(slot); } if (!playerMove.PlayerScript.IsGhost) { //dirty way to follow gibs. change this when implementing proper gibbing, perhaps make it follow brain var gibsToFollow = MatrixManager.GetAt <RawMeat>(transform.position.CutToInt(), true); if (gibsToFollow.Count > 0) { var gibs = gibsToFollow[0]; FollowCameraMessage.Send(gameObject, gibs.gameObject); var gibsIntegrity = gibs.GetComponent <Integrity>(); if (gibsIntegrity != null) { //Stop cam following gibs if they are destroyed gibsIntegrity.OnWillDestroyServer.AddListener(x => FollowCameraMessage.Send(gameObject, null)); } } } playerMove.PlayerScript.pushPull.VisibleState = false; }
private bool HasPlayersAt(Vector3 stateWorldPosition, out PlayerScript firstPlayer) { firstPlayer = null; var intPos = Vector3Int.RoundToInt((Vector2)stateWorldPosition); var players = MatrixManager.GetAt<PlayerScript>(intPos, isServer : true); if (players.Count == 0) { return false; } for (var i = 0; i < players.Count; i++) { var player = players[i]; if (player.registerTile.IsPassable(true) || intPos != Vector3Int.RoundToInt(player.PlayerSync.ServerState.WorldPosition) ) { continue; } firstPlayer = player; return true; } return false; }
private void DestroyObjects(IEnumerable <Vector3Int> coords) { var damage = 100; if (CurrentStage == SingularityStages.Stage5 || CurrentStage == SingularityStages.Stage4) { damage *= (int)CurrentStage; } foreach (var coord in coords) { var objects = MatrixManager.GetAt <RegisterTile>(coord, true); foreach (var objectToMove in objects) { if (objectToMove.gameObject == gameObject) { continue; } if (objectToMove.ObjectType == ObjectType.Player && objectToMove.TryGetComponent <PlayerHealthV2>(out var health) && health != null) { if (health.RegisterPlayer.PlayerScript != null && health.RegisterPlayer.PlayerScript.mind != null && health.RegisterPlayer.PlayerScript.mind.occupation != null && health.RegisterPlayer.PlayerScript.mind.occupation == OccupationList.Instance.Get(JobType.CLOWN)) { health.Gib(); ChangePoints(DMMath.Prob(50) ? -1000 : 1000); return; } health.Gib(); ChangePoints(100); }
/// <summary> /// Gets all reachable items, including items in player's hands and pockets. /// </summary> /// <param name="networkSide">On which side we're executing the method?</param> /// <returns>All reachable items.</returns> public List <CraftingIngredient> GetPossibleIngredients(NetworkSide networkSide) { List <CraftingIngredient> possibleIngredients = MatrixManager.GetReachableAdjacent <CraftingIngredient>( playerScript.PlayerSync.ClientPosition, networkSide == NetworkSide.Server ); possibleIngredients.AddRange(MatrixManager.GetAt <CraftingIngredient>( playerScript.PlayerSync.ClientPosition, networkSide == NetworkSide.Server )); foreach (ItemSlot handSlot in playerScript.DynamicItemStorage.GetHandSlots()) { if ( handSlot.ItemObject != null && handSlot.ItemObject.TryGetComponent(out CraftingIngredient possibleIngredient) ) { possibleIngredients.Add(possibleIngredient); } } foreach (ItemSlot pocketsSlot in playerScript.DynamicItemStorage.GetPocketsSlots()) { if ( pocketsSlot.ItemObject != null && pocketsSlot.ItemObject.TryGetComponent(out CraftingIngredient possibleIngredient) ) { possibleIngredients.Add(possibleIngredient); } } return(possibleIngredients); }
/// <summary> /// Gets all reachable reagent containers. /// </summary> /// <returns></returns> public List <ReagentContainer> GetReagentContainers() { List <ReagentContainer> reagentContainers = MatrixManager.GetReachableAdjacent <ReagentContainer>( playerScript.PlayerSync.ClientPosition, true ); reagentContainers.AddRange(MatrixManager.GetAt <ReagentContainer>( PlayerScript.PlayerSync.ClientPosition, true )); foreach (ItemSlot handSlot in playerScript.DynamicItemStorage.GetHandSlots()) { if ( handSlot.ItemObject != null && handSlot.ItemObject.TryGetComponent(out ReagentContainer reagentContainer) ) { reagentContainers.Add(reagentContainer); } } foreach (ItemSlot pocketsSlot in playerScript.DynamicItemStorage.GetPocketsSlots()) { if ( pocketsSlot.ItemObject != null && pocketsSlot.ItemObject.TryGetComponent(out ReagentContainer reagentContainer) ) { reagentContainers.Add(reagentContainer); } } return(reagentContainers); }
public void ServerPerformInteraction(HandApply interaction) { if (anchored) { SoundManager.PlayNetworkedAtPos("Wrench", registerTile.WorldPositionServer, 1f); Detach(); } else { var foundPipes = MatrixManager.GetAt <Pipe>(registerTile.WorldPositionServer, true); for (int i = 0; i < foundPipes.Count; i++) { Pipe foundPipe = foundPipes[i]; if (foundPipe.anchored) { SoundManager.PlayNetworkedAtPos("Wrench", registerTile.WorldPositionServer, 1f); pipe = foundPipe; ToggleAnchored(true); UpdateManager.Add(CallbackType.UPDATE, UpdateMe); UpdateMe(); break; } } } }
/// <summary> /// Detect generators /// </summary> private void DetectGenerators() { var enumValues = Enum.GetValues(typeof(Direction)); foreach (var value in enumValues) { if (connectedGenerator.ContainsKey((Direction)value)) { continue; } for (int i = 1; i <= detectionRange; i++) { var pos = registerTile.WorldPositionServer + GetCoordFromDirection((Direction)value) * i; var objects = MatrixManager.GetAt <FieldGenerator>(pos, true); //If there isn't a field generator but it is impassable dont check further if (objects.Count == 0 && !MatrixManager.IsPassableAtAllMatricesOneTile(pos, true, false)) { break; } if (objects.Count > 0 && objects[0].isWelded) { //Shouldn't be more than one, but just in case pick first //Add to connected gen dictionary connectedGenerator.Add((Direction)value, new Tuple <GameObject, bool>(objects[0].gameObject, false)); objects[0].integrity.OnWillDestroyServer.AddListener(OnConnectedDestroy); break; } } } }
private bool ValidateFloating(Vector3 origin, Vector3 goal) { // Logger.Log( $"{gameObject.name} check {origin}->{goal}. Speed={serverState.Speed}" ); var startPosition = Vector3Int.RoundToInt(origin); var targetPosition = Vector3Int.RoundToInt(goal); var info = serverState.ActiveThrow; IReadOnlyCollection <LivingHealthBehaviour> creaturesToHit = Vector3Int.RoundToInt(serverState.ActiveThrow.OriginWorldPos) == targetPosition ? null : LivingCreaturesInPosition(targetPosition); if (serverState.Speed > SpeedHitThreshold) { OnHit(targetPosition, info, creaturesToHit); DamageTile(goal, MatrixManager.GetDamageableTilemapsAt(targetPosition)); } if (CanDriftTo(startPosition, targetPosition, isServer: true)) { //if we can keep drifting and didn't hit anything, keep floating. If we did hit something, only stop if we are impassable (we bonked something), //otherwise keep drifting through (we sliced / glanced off them) return((creaturesToHit == null || creaturesToHit.Count == 0) || (registerTile && registerTile.IsPassable(true))); } IReadOnlyCollection <DisposalBin> bins = MatrixManager.GetAt <DisposalBin>(targetPosition, isServer: true) .Where(bin => CanHitObject(bin)).ToArray(); if (bins.Count > 0) { bins.First().OnFlyingObjectHit(gameObject); } return(false); }
public override bool CastSpellServer(ConnectedPlayer caster) { if (!base.CastSpellServer(caster)) { return(false); } var buckleable = MatrixManager.GetAt <BuckleInteract>(caster.Script.AssumedWorldPos, true).FirstOrDefault(); if (buckleable == null) { return(false); } var directional = buckleable.GetComponent <Rotatable>(); if (directional) { directional.FaceDirection(caster.Script.CurrentDirection); } buckleable.BucklePlayer(caster.Script); return(true); }
private void DestroyObjects(IEnumerable <Vector3Int> coords) { var damage = 100; if (CurrentStage == SingularityStages.Stage5 || CurrentStage == SingularityStages.Stage4) { damage *= (int)CurrentStage; } foreach (var coord in coords) { var objects = MatrixManager.GetAt <RegisterTile>(coord, true); foreach (var objectToMove in objects) { if (objectToMove.gameObject == gameObject) { continue; } if (objectToMove.ObjectType == ObjectType.Player && objectToMove.TryGetComponent <PlayerHealth>(out var health) && health != null) { health.ServerGibPlayer(); ChangePoints(100); }
private bool TryFindParts() { var enumValues = Enum.GetValues(typeof(OrientationEnum)); bool correctArrangement = false; //For each set up direction foreach (var enumDirection in enumValues) { //Check to see if the system has been set up foreach (var section in machineBluePrint) { var coord = section.Key; for (int i = 1; i <= (int)enumDirection; i++) { coord = RotateVector90(coord).To2Int(); } var objects = MatrixManager.GetAt <ParticleAcceleratorPart>(registerTile.WorldPositionServer + coord.To3Int(), true); if (objects.Count > 0 && section.Value == objects[0].ParticleAcceleratorType) { //Correct Part there woo but now check status if (objects[0].CurrentState == ParticleAcceleratorState.Frame || objects[0].CurrentState == ParticleAcceleratorState.Wired || objects[0].Directional.CurrentDirection.AsEnum() != (OrientationEnum)enumDirection || objects[0].ParticleAcceleratorType != section.Value) { //Frame or wired are not ready and isn't right direction so failed check correctArrangement = false; connectedParts.Clear(); break; } //In right position and correct state and direction so this part passed, check other coords for faults now correctArrangement = true; connectedParts.Add(objects[0]); continue; } //Failed check for this direction as all parts need to be correct correctArrangement = false; connectedParts.Clear(); break; } if (correctArrangement) { //This arrangement succeeded, dont need to check other directions orientation = Orientation.FromEnum((OrientationEnum)enumDirection); break; } } if (correctArrangement == false) { //No directions succeeded :( return(false); } return(true); }
/// Lists objects to be damaged on given tile. Prob should be moved elsewhere private IReadOnlyCollection <LivingHealthBehaviour> LivingCreaturesInPosition(Vector3Int position) { return(MatrixManager.GetAt <LivingHealthBehaviour>(position, isServer: true)? .Where(creature => creature.IsDead == false && CanHitObject(creature)) .ToArray()); }
private ValidationResult AllValidate(TargetedInteraction toValidate, NetworkSide side) { var position = toValidate.TargetObject.transform.position.CutToInt(); return(MatrixManager.GetAt <T>(position, side == NetworkSide.SERVER).Any(criteria) == shouldAnyMatch ? ValidationResult.SUCCESS : ValidationResult.FAIL); }
private void TileReachedServer(Vector3Int worldPos) { var crossedItems = MatrixManager.GetAt <Pickupable>(worldPos, true); foreach (var item in crossedItems) { Inventory.ServerAdd(item, storage.GetBestSlotFor(item)); } }
private void TileReachedServer(Vector3Int worldPos) { var crossedItems = MatrixManager.GetAt <ItemAttributesV2>(worldPos, true); foreach (var crossedItem in crossedItems) { AttemptToStore(crossedItem.gameObject); } }
public override bool Interact(GameObject originator, Vector3 position, string hand) { if (!CanUse(originator, hand, position, false)) { return(false); } if (!isServer) { //ask server to perform the interaction InteractMessage.Send(gameObject, position, hand); return(true); } PlayerNetworkActions pna = originator.GetComponent <PlayerNetworkActions>(); GameObject handObj = pna.Inventory[hand].Item; if (handObj && handObj.GetComponent <WrenchTrigger>()) { if (connector == null) { var foundConnectors = MatrixManager.GetAt <Connector>(registerTile.WorldPositionServer, true); for (int n = 0; n < foundConnectors.Count; n++) { var conn = foundConnectors[n]; if (conn.objectBehaviour.isNotPushable) { connector = conn; connector.ConnectCanister(this); connectorRenderer.sprite = connectorSprite; objectBehaviour.isNotPushable = true; return(true); } } } else { connector.DisconnectCanister(); connectorRenderer.sprite = null; connector = null; objectBehaviour.isNotPushable = false; return(true); } } //container.Opened = !container.Opened; base.Interact(originator, position, hand); /* * string msg = container.Opened ? $"The valve is open, outputting at {container.ReleasePressure} kPa." : "The valve is closed."; * UpdateChatMessage.Send(originator, ChatChannel.Examine, msg); */ return(true); }
protected override InteractionResult ServerPerformInteraction(HandApply interaction) { var playerMoveAtPosition = MatrixManager.GetAt <PlayerMove>(transform.position.CutToInt(), true)?.First(pm => pm.IsRestrained); //cannot use the CmdUnrestrain because commands are only allowed to be invoked by local player playerMoveAtPosition.Unrestrain(); //the above will then invoke onunbuckle as it was the callback passed to Restrain return(InteractionResult.SOMETHING_HAPPENED); }
private void OnWillDestroyServer(DestructionInfo info) { //release the player if (isOccupied) { var playerMoveAtPosition = MatrixManager.GetAt <PlayerMove>(transform.position.CutToInt(), true) ?.First(pm => pm.IsBuckled); playerMoveAtPosition.Unbuckle(); } }
public void CleanTile(Vector3 spatsPos) { Vector3Int targetWorldIntPos = spatsPos.CutToInt(); var bloodSpats = MatrixManager.GetAt <BloodSplat>(targetWorldIntPos); for (var i = 0; i < bloodSpats.Count; i++) { bloodSpats[i].DisappearFromWorldServer(); } }
public void ServerPerformInteraction(HandApply interaction) { SoundManager.PlayNetworkedAtPos("Click01", interaction.TargetObject.WorldPosServer()); var playerMoveAtPosition = MatrixManager.GetAt <PlayerMove>(transform.position.CutToInt(), true)?.First(pm => pm.IsBuckled); //cannot use the CmdUnrestrain because commands are only allowed to be invoked by local player playerMoveAtPosition.Unbuckle(); //the above will then invoke onunbuckle as it was the callback passed to Restrain }
private void DamageObjects(Vector3Int worldPosition, int damage) { var damagedObjects = (MatrixManager.GetAt <Integrity>(worldPosition, true) //only damage each thing once .Distinct()); foreach (var damagedObject in damagedObjects) { damagedObject.ApplyDamage(damage, AttackType.Bomb, DamageType.Burn); } }
private void DamageLivingThings(Vector3Int worldPosition, int damage) { var damagedLivingThings = (MatrixManager.GetAt <LivingHealthBehaviour>(worldPosition, true) //only damage each thing once .Distinct()); foreach (var damagedLiving in damagedLivingThings) { damagedLiving.ApplyDamage(gameObject, damage, AttackType.Bomb, DamageType.Burn); } }
/// Lists objects to be damaged on given tile. Prob should be moved elsewhere private bool HittingSomething(Vector3Int atPos, GameObject thrownBy, out List <LivingHealthBehaviour> victims) { //Not damaging anything at launch tile if (Vector3Int.RoundToInt(serverState.ActiveThrow.OriginPos) == atPos) { victims = null; return(false); } var objectsOnTile = MatrixManager.GetAt <LivingHealthBehaviour>(atPos); if (objectsOnTile != null) { var damageables = new List <LivingHealthBehaviour>(); for (var i = 0; i < objectsOnTile.Count; i++) { LivingHealthBehaviour obj = objectsOnTile[i]; //Skip thrower for now if (obj.gameObject == thrownBy) { Logger.Log($"{thrownBy.name} not hurting himself", Category.Throwing); continue; } //Skip dead bodies if (obj.IsDead) { continue; } var commonTransform = obj.GetComponent <IPushable>(); if (commonTransform != null) { if (this.ServerImpulse.To2Int() == commonTransform.ServerImpulse.To2Int() && this.SpeedServer <= commonTransform.SpeedServer) { Logger.LogTraceFormat("{0} not hitting {1} as they fly in the same direction", Category.Throwing, gameObject.name, obj.gameObject.name); continue; } } damageables.Add(obj); } if (damageables.Count > 0) { victims = damageables; return(true); } } victims = null; return(false); }
private void OnWillDestroyServer(DestructionInfo info) { //release the player if (occupant > 0) { //fixme: InvalidOperationException - Sequence contains no matching element var playerMoveAtPosition = MatrixManager.GetAt <PlayerMove>(transform.position.CutToInt(), true) ?.First(pm => pm.IsBuckled); playerMoveAtPosition.Unbuckle(); } }
public void ServerPerformInteraction(HandApply interaction) { if (MatrixManager.GetAt <PlayerMove>(interaction.TargetObject, NetworkSide.Server) .Any(pm => pm.IsBuckled)) { Chat.AddExamineMsgFromServer(interaction.Performer, $"You cannot deconstruct this while it is occupied!"); return; } ToolUtils.ServerPlayToolSound(interaction); Disassemble(interaction); }
private void EmpThings(Vector3Int worldPosition, int damage) { foreach (var thing in MatrixManager.GetAt <Integrity>(worldPosition, true).Distinct()) { EmpThing(thing.gameObject, damage); } foreach (var thing in MatrixManager.GetAt <LivingHealthMasterBase>(worldPosition, true).Distinct()) { EmpThing(thing.gameObject, damage); } }
private void CheckDamagedThings(Vector2 worldPosition) { //TODO: Does this damage things in lockers? damagedLivingThings.AddRange(MatrixManager.GetAt <LivingHealthBehaviour>(worldPosition.RoundToInt(), true) //only damage each thing once .Distinct()); damagedObjects.AddRange(MatrixManager.GetAt <Integrity>(worldPosition.RoundToInt(), true) //dont damage this grenade .Where(i => i.gameObject != gameObject) //only damage each thing once .Distinct()); }
//Coppied from mop code, cleans decals off of tiles public static void CleanTile(Vector3 worldPos) { var worldPosInt = worldPos.CutToInt(); var matrix = MatrixManager.AtPoint(worldPosInt); var localPosInt = MatrixManager.WorldToLocalInt(worldPosInt, matrix); var floorDecals = MatrixManager.GetAt <FloorDecal>(worldPosInt); for (var i = 0; i < floorDecals.Count; i++) { floorDecals[i].DisappearFromWorldServer(); } }
private void PushPullObjects() { int distance; switch (currentStage) { case SingularityStages.Stage0: distance = 1; break; case SingularityStages.Stage1: distance = 2; break; case SingularityStages.Stage2: distance = 3; break; case SingularityStages.Stage3: distance = 8; break; case SingularityStages.Stage4: distance = 10; break; case SingularityStages.Stage5: distance = 14; break; default: distance = 1; break; } foreach (var tile in EffectShape.CreateEffectShape(EffectShapeType.Circle, registerTile.WorldPositionServer, distance).ToList()) { var objects = MatrixManager.GetAt <PushPull>(tile, true); foreach (var objectToMove in objects) { if (objectToMove.registerTile.ObjectType == ObjectType.Item) { ThrowItem(objectToMove, registerTile.WorldPositionServer - objectToMove.registerTile.WorldPositionServer); } else { PushObject(objectToMove, registerTile.WorldPositionServer - objectToMove.registerTile.WorldPositionServer); } } } }