예제 #1
0
        //Where is the target? Is there something in the way we can break
        //to get to the target?
        private bool CheckForAttackTarget()
        {
            if (followTarget != null)
            {
                if (mobAI.IsDead || mobAI.IsUnconscious)
                {
                    Deactivate();
                    followTarget = null;
                    return(false);
                }

                var followLivingBehaviour = followTarget.GetComponent <LivingHealthBehaviour>();
                var distanceToTarget      = Vector3.Distance(followTarget.transform.position, transform.position);
                if (followLivingBehaviour != null)
                {
                    //When to stop following on the server:
                    if (followLivingBehaviour.IsDead || distanceToTarget > 30f)
                    {
                        Deactivate();
                        followTarget = null;
                        return(false);
                    }
                }

                var dirToTarget = (followTarget.position - transform.position).normalized;
                var hitInfo     =
                    MatrixManager.Linecast(transform.position + dirToTarget, LayerTypeSelection.Windows, checkMask, followTarget.position);
                //	Debug.DrawLine(transform.position + dirToTarget, followTarget.position, Color.blue, 10f);
                if (hitInfo.CollisionHit.GameObject != null)
                {
                    if (Vector3.Distance(transform.position, hitInfo.TileHitWorld) < 1.5f)
                    {
                        var dir = (hitInfo.TileHitWorld - transform.position).normalized;

                        //Only hit target
                        if (onlyHitTarget)
                        {
                            var healthBehaviour = hitInfo.CollisionHit.GameObject.transform.GetComponent <LivingHealthBehaviour>();
                            if (hitInfo.CollisionHit.GameObject.transform != followTarget || healthBehaviour.IsDead)
                            {
                                return(false);
                            }
                            else
                            {
                                AttackFlesh(dir, healthBehaviour);
                                return(true);
                            }
                        }

                        //What to do with player hit?
                        if (hitInfo.CollisionHit.GameObject.transform.gameObject.layer == playersLayer)
                        {
                            var healthBehaviour = hitInfo.CollisionHit.GameObject.transform.GetComponent <LivingHealthBehaviour>();
                            if (healthBehaviour.IsDead)
                            {
                                return(false);
                            }

                            AttackFlesh(dir, healthBehaviour);

                            if (followTarget.gameObject.layer == playersLayer)
                            {
                                if (followTarget != hitInfo.CollisionHit.GameObject.transform)
                                {
                                    if (targetOtherPlayersWhoGetInWay)
                                    {
                                        followTarget = hitInfo.CollisionHit.GameObject.transform;
                                    }
                                }
                            }

                            return(true);
                        }

                        //What to do with NPC hit?
                        if (hitInfo.CollisionHit.GameObject.transform.gameObject.layer == npcLayer)
                        {
                            var mobAi = hitInfo.CollisionHit.GameObject.transform.GetComponent <MobAI>();
                            if (mobAi != null && mobAI != null)
                            {
                                if (mobAi.mobName.Equals(mobAI.mobName, StringComparison.OrdinalIgnoreCase))
                                {
                                    return(false);
                                }
                            }

                            var healthBehaviour = hitInfo.CollisionHit.GameObject.transform.GetComponent <LivingHealthBehaviour>();
                            if (healthBehaviour != null)
                            {
                                if (healthBehaviour.IsDead)
                                {
                                    return(false);
                                }

                                AttackFlesh(dir, healthBehaviour);
                                return(true);
                            }
                        }

                        //What to do with Tile hits?
                        if (distanceToTarget > 4.5f)
                        {
                            //Don't bother, the target is too far away to warrant a decision to break a tile
                            return(false);
                        }

                        AttackTile(hitInfo.TileHitWorld.RoundToInt(), dir);
                        return(true);
                    }
                }
            }

            return(false);
        }
예제 #2
0
 /// Same as ExposeHotspot but allows providing a world position and handles the conversion
 public void ExposeHotspotWorldPosition(Vector2Int tileWorldPosition, float temperature, float volume)
 {
     ExposeHotspot(MatrixManager.WorldToLocalInt(tileWorldPosition.To3Int(), MatrixManager.Get(matrix)), temperature, volume);
 }
예제 #3
0
    public void ServerPerformInteraction(ConnectionApply interaction)
    {
        var cableCoil = interaction.HandObject.GetComponent <CableCoil>();

        if (cableCoil != null)
        {
            Vector3Int worldPosInt = Vector3Int.RoundToInt(interaction.WorldPositionTarget);
            MatrixInfo matrix      = MatrixManager.AtPoint(worldPosInt, true);
            var        localPosInt = MatrixManager.WorldToLocalInt(worldPosInt, matrix);

            // if there is no matrix or IsClearUnderfloor == false - return
            if (matrix.Matrix == null || !matrix.Matrix.IsClearUnderfloorConstruction(localPosInt, true))
            {
                return;
            }

            Connection WireEndB = interaction.WireEndB;
            Connection WireEndA = interaction.WireEndA;

            if (WireEndB != Connection.NA)
            {
                // high voltage cables can't connect diagonally
                if (CableType == WiringColor.high)
                {
                    switch (WireEndB)
                    {
                    case Connection.NorthEast:
                        return;

                    case Connection.NorthWest:
                        return;

                    case Connection.SouthWest:
                        return;

                    case Connection.SouthEast:
                        return;
                    }
                    switch (WireEndA)
                    {
                    case Connection.NorthEast:
                        return;

                    case Connection.NorthWest:
                        return;

                    case Connection.SouthWest:
                        return;

                    case Connection.SouthEast:
                        return;
                    }
                }

                var econs = interaction.Performer.GetComponentInParent <Matrix>().GetElectricalConnections(localPosInt);
                foreach (var con in econs)
                {
                    if (con.WireEndA == Connection.Overlap || con.WireEndB == Connection.Overlap)
                    {
                        if (con.WireEndA == WireEndB || con.WireEndB == WireEndB)
                        {
                            Chat.AddExamineMsgToClient("There is already a cable at that position");
                            econs.Clear();
                            ElectricalPool.PooledFPCList.Add(econs);
                            return;
                        }

                        foreach (var Econ in econs)
                        {
                            if (Econ.WireEndA == WireEndB || Econ.WireEndB == WireEndB)
                            {
                                if (con.WireEndA == Econ.WireEndA || con.WireEndB == Econ.WireEndA)
                                {
                                    Chat.AddExamineMsgToClient("There is already a cable at that position");
                                    econs.Clear();
                                    ElectricalPool.PooledFPCList.Add(econs);
                                    return;
                                }
                                else if (con.WireEndA == Econ.WireEndB || con.WireEndB == Econ.WireEndB)
                                {
                                    Chat.AddExamineMsgToClient("There is already a cable at that position");
                                    econs.Clear();
                                    ElectricalPool.PooledFPCList.Add(econs);
                                    return;
                                }
                            }
                        }
                    }
                }

                econs.Clear();
                ElectricalPool.PooledFPCList.Add(econs);
                BuildCable(localPosInt, interaction.Performer.transform.parent, WireEndA, WireEndB, interaction);
                Inventory.ServerConsume(interaction.HandSlot, 1);
            }
        }
    }
예제 #4
0
 /// <Summary>
 /// Use World positions
 /// </Summary>
 private bool CanDriftTo(Vector3Int originPos, Vector3Int targetPos)
 {
     return(MatrixManager.IsPassableAt(originPos, targetPos, false));
 }
예제 #5
0
 private void SyncMatrix()
 {
     registerTile.ParentNetId = MatrixManager.Get(serverState.MatrixId).NetId;
 }
예제 #6
0
    /// <summary>
    /// Spawns a ghost for the indicated mind's body and transfers the connection's control to it.
    /// </summary>
    /// <param name="conn"></param>
    /// <param name="oldBody"></param>
    /// <param name="characterSettings"></param>
    /// <param name="occupation"></param>
    /// <returns></returns>
    public static void ServerSpawnGhost(Mind forMind)
    {
        if (forMind == null)
        {
            Logger.LogError("Mind was null for ServerSpawnGhost", Category.Ghosts);
            return;
        }
        //determine where to spawn the ghost
        var body = forMind.GetCurrentMob();

        if (body == null)
        {
            Logger.LogError("Body was null for ServerSpawnGhost", Category.Ghosts);
            return;
        }

        var settings     = body.GetComponent <PlayerScript>().characterSettings;
        var connection   = body.GetComponent <NetworkIdentity>().connectionToClient;
        var registerTile = body.GetComponent <RegisterTile>();

        if (registerTile == null)
        {
            Logger.LogErrorFormat("Cannot spawn ghost for body {0} because it has no registerTile", Category.Ghosts,
                                  body.name);
            return;
        }

        Vector3Int spawnPosition = TransformState.HiddenPos;
        var        objBeh        = body.GetComponent <ObjectBehaviour>();

        if (objBeh != null)
        {
            spawnPosition = objBeh.AssumedWorldPositionServer();
        }

        if (spawnPosition == TransformState.HiddenPos)
        {
            //spawn ghost at occupation location if we can't determine where their body is
            Transform spawnTransform = SpawnPoint.GetRandomPointForJob(forMind.occupation.JobType, true);
            if (spawnTransform == null)
            {
                Logger.LogErrorFormat("Unable to determine spawn position for occupation {1}. Cannot spawn ghost.", Category.Ghosts,
                                      forMind.occupation.DisplayName);
                return;
            }

            spawnPosition = spawnTransform.transform.position.CutToInt();
        }

        var matrixInfo      = MatrixManager.AtPoint(spawnPosition, true);
        var parentTransform = matrixInfo.Objects;

        //using parentTransform.rotation rather than Quaternion.identity because objects should always
        //be upright w.r.t.  localRotation, NOT world rotation
        var ghost = UnityEngine.Object.Instantiate(CustomNetworkManager.Instance.ghostPrefab, spawnPosition, parentTransform.rotation,
                                                   parentTransform);

        forMind.Ghosting(ghost);

        ServerTransferPlayer(connection, ghost, body, Event.GhostSpawned, settings);


        //fire all hooks
        var info = SpawnInfo.Ghost(forMind.occupation, settings, CustomNetworkManager.Instance.ghostPrefab,
                                   SpawnDestination.At(spawnPosition, parentTransform));

        Spawn._ServerFireClientServerSpawnHooks(SpawnResult.Single(info, ghost));

        if (PlayerList.Instance.IsAdmin(forMind.ghost.connectedPlayer))
        {
            var adminItemStorage = AdminManager.Instance.GetItemSlotStorage(forMind.ghost.connectedPlayer);
            adminItemStorage.ServerAddObserverPlayer(ghost);
            ghost.GetComponent <GhostSprites>().SetAdminGhost();
        }
    }
예제 #7
0
 public LightMatrixManager(MatrixManager manager)
 {
     this.manager = manager;
     Camera       = new BasicCamera(new Vector3(0, 0, -20), new Vector3(0, 0, 0), new Vector3(0, 1, 0));
     Projection   = new BasicProjectionMatrixProvider();
 }
예제 #8
0
    public void ServerPerformInteraction(PositionalHandApply interaction)
    {
        var        roundTargetWorldPosition = interaction.WorldPositionTarget.RoundToInt();
        MatrixInfo matrix = MatrixManager.AtPoint(roundTargetWorldPosition, true);

        if (matrix?.Matrix == null)
        {
            return;
        }
        if (!MatrixManager.IsWallAt(roundTargetWorldPosition, true))
        {
            return;
        }

        Vector3Int      PlaceDirection = interaction.Performer.Player().Script.WorldPos - roundTargetWorldPosition;
        OrientationEnum FaceDirection;

        //is there a wall in the direction of the new wallmount? taking into account diagonal clicking
        var tileInFront = roundTargetWorldPosition + new Vector3Int(PlaceDirection.x, 0, 0);

        if (!MatrixManager.IsWallAt(tileInFront, true))
        {
            if (PlaceDirection.x > 0)
            {
                FaceDirection = OrientationEnum.Right_By90;
            }
            else
            {
                FaceDirection = OrientationEnum.Left_By270;
            }
        }
        else
        {
            tileInFront = roundTargetWorldPosition + new Vector3Int(0, PlaceDirection.y, 0);
            if (!MatrixManager.IsWallAt(tileInFront, true))
            {
                if (PlaceDirection.y > 0)
                {
                    FaceDirection = OrientationEnum.Up_By0;
                }
                else
                {
                    FaceDirection = OrientationEnum.Down_By180;
                }
            }
            else
            {
                return;
            }
        }

        if (IsWallProtrusion)
        {
            roundTargetWorldPosition = tileInFront;
        }

        GameObject WallMount   = Spawn.ServerPrefab(WallMountToSpawn, roundTargetWorldPosition, interaction.Performer.transform.parent, spawnItems: false).GameObject;
        var        Directional = WallMount.GetComponent <Rotatable>();

        if (Directional != null)
        {
            Directional.FaceDirection(FaceDirection);
        }

        Inventory.ServerConsume(interaction.HandSlot, 1);

        var construction = WallMount.GetComponent <LightFixtureConstruction>();

        if (construction != null)
        {
            construction.ServerSetState(LightFixtureConstruction.State.initial);
        }
    }
예제 #9
0
    private PlayerState NextStateServer(PlayerState state, PlayerAction action)
    {
        //Check if there is a bump interaction according to the server
        BumpType serverBump = CheckSlideAndBump(state, ref action);

        //Client only needs to check whether movement was prevented, specific type of bump doesn't matter
        bool isClientBump = action.isBump;

        //we only lerp back if the client thinks it's passable  but server does not...if client
        //thinks it's not passable and server thinks it's passable, then it's okay to let the client continue
        if (!isClientBump && serverBump != BumpType.None)
        {
            Logger.LogWarningFormat("isBump mismatch, resetting: C={0} S={1}", Category.Movement, isClientBump, serverBump != BumpType.None);
            RollbackPosition();
        }
        if (isClientBump || serverBump != BumpType.None)
        {
            // we bumped something, an interaction might occur
            // try pushing things / opening doors
            BumpInteract(state.WorldPosition, (Vector2)action.Direction());

            playerSprites.FaceDirection(Orientation.From(action.Direction()));
            return(state);
        }

        if (IsNonStickyServer)
        {
            PushPull pushable;
            if (IsAroundPushables(serverState, out pushable))
            {
                StartCoroutine(InteractSpacePushable(pushable, action.Direction()));
            }
            return(state);
        }

        if (action.isNonPredictive)
        {
            Logger.Log("Ignored action marked as Non-predictive while being indoors", Category.Movement);
            return(state);
        }

        bool        matrixChangeDetected;
        PlayerState nextState = NextState(state, action, out matrixChangeDetected);

        if (!matrixChangeDetected)
        {
            return(nextState);
        }

        //todo: subscribe to current matrix rotations on spawn
        var newMatrix = MatrixManager.Get(nextState.MatrixId);

        Logger.Log($"Matrix will change to {newMatrix}", Category.Movement);
        if (newMatrix.MatrixMove)
        {
            //Subbing to new matrix rotations
            newMatrix.MatrixMove.OnRotate.AddListener(OnRotation);
            //				Logger.Log( $"Registered rotation listener to {newMatrix.MatrixMove}" );
        }

        //Unsubbing from old matrix rotations
        MatrixMove oldMatrixMove = MatrixManager.Get(Matrix).MatrixMove;

        if (oldMatrixMove)
        {
            //				Logger.Log( $"Unregistered rotation listener from {oldMatrixMove}" );
            oldMatrixMove.OnRotate.RemoveListener(OnRotation);
        }

        return(nextState);
    }
예제 #10
0
    /// <summary>
    /// Release reagents at provided coordinates, making them react with world
    /// </summary>
    public void ReagentReact(ReagentMix reagents, Vector3Int worldPosInt, Vector3Int localPosInt)
    {
        if (MatrixManager.IsTotallyImpassable(worldPosInt, true))
        {
            return;
        }

        bool didSplat = false;

        foreach (var reagent in reagents.reagents)
        {
            if (reagent.Value < 1)
            {
                continue;
            }

            switch (reagent.Key.Name)
            {
            case "Water":
            {
                matrix.ReactionManager.ExtinguishHotspot(localPosInt);

                foreach (var livingHealthBehaviour in matrix.Get <LivingHealthBehaviour>(localPosInt, true))
                {
                    livingHealthBehaviour.Extinguish();
                }

                Clean(worldPosInt, localPosInt, true);
                break;
            }

            case "SpaceCleaner":
                Clean(worldPosInt, localPosInt, false);
                break;

            case "WeldingFuel":
                //temporary: converting spilled fuel to plasma
                Get(localPosInt).GasMix.AddGas(Gas.Plasma, reagent.Value);
                break;

            case "Lube":
            {
                //( ͡° ͜ʖ ͡°)
                if (!Get(localPosInt).IsSlippery)
                {
                    EffectsFactory.WaterSplat(worldPosInt);
                    MakeSlipperyAt(localPosInt, false);
                }

                break;
            }

            default:
            {
                //for all other things leave a chem splat
                if (!didSplat)
                {
                    EffectsFactory.ChemSplat(worldPosInt);
                    didSplat = true;
                }

                break;
            }
            }
        }
    }
예제 #11
0
 private static Transform DefaultParent(Transform parent, Vector3?worldPos)
 {
     return(parent != null ? parent : MatrixManager.GetDefaultParent(worldPos, true));
 }
예제 #12
0
 private void LoadTurf()
 {
     metaDataLayer = MatrixManager.AtPoint(registerTile.WorldPositionServer, true).MetaDataLayer;
     metaNode      = metaDataLayer.Get(registerTile.WorldPositionServer, false);
 }
예제 #13
0
        private void CreateHotSpot()
        {
            var reactionManager = MatrixManager.AtPoint(currentTileWorldPos, true).ReactionManager;

            reactionManager.ExposeHotspotWorldPosition(currentTileWorldPos.To2Int());
        }
예제 #14
0
 private static Vector3 WorldToLocal(Component source, Vector3 position)
 {
     return(MatrixManager.WorldToLocal(position, MatrixManager.Get(source.GetComponent <Matrix>())));
 }
예제 #15
0
        public void Process()
        {
            float Damagedealt    = AngleAndIntensity.magnitude;
            float EnergyExpended = 0;
            var   v3int          = new Vector3Int(Location.x, Location.y, 0);

            var metaTileMap = matrix.MetaTileMap;

            if (metaTileMap == null)
            {
                return;
            }

            EnergyExpended = metaTileMap.ApplyDamage(v3int, Damagedealt,
                                                     MatrixManager.LocalToWorldInt(v3int, matrix.MatrixInfo), AttackType.Bomb) * 0.375f;

            // Prevents a perpetual motion explosion
            if (EnergyExpended <= 0.375f)
            {
                EnergyExpended = 0.375f;
            }

            if (Damagedealt > 100)
            {
                var Node = matrix.GetMetaDataNode(v3int);
                if (Node != null)
                {
                    foreach (var electricalData in Node.ElectricalData)
                    {
                        electricalData.InData.DestroyThisPlease();
                    }

                    SavedPipes.Clear();
                    SavedPipes.AddRange(Node.PipeData);
                    foreach (var Pipe in SavedPipes)
                    {
                        Pipe.pipeData.DestroyThis();
                    }
                }
            }


            foreach (var integrity in matrix.Get <Integrity>(v3int, true))
            {
                //Throw items
                //And do damage to objects
                integrity.ApplyDamage(Damagedealt, AttackType.Bomb, DamageType.Brute);
            }

            foreach (var player in matrix.Get <ObjectBehaviour>(v3int, ObjectType.Player, true))
            {
                // do damage
                player.GetComponent <PlayerHealthV2>().ApplyDamageAll(null, Damagedealt, AttackType.Bomb, DamageType.Brute);
            }

            foreach (var line in PresentLines)
            {
                line.ExplosionStrength -= EnergyExpended * (line.ExplosionStrength / Damagedealt);
            }
            AngleAndIntensity = Vector2.zero;
        }
예제 #16
0
        public void DestroyThis()
        {
            if (MonoPipe == null)
            {
                var Transform = matrix.UnderFloorLayer.GetMatrix4x4(pipeNode.NodeLocation, pipeNode.RelatedTile);
                var pipe      = Spawn.ServerPrefab(pipeNode.RelatedTile.SpawnOnDeconstruct, MatrixManager.LocalToWorld(pipeNode.NodeLocation, matrix),
                                                   localRotation: PipeDeconstruction.QuaternionFromMatrix(Transform)).GameObject;
                var itempipe = pipe.GetComponent <PipeItemTile>();
                itempipe.Colour = matrix.UnderFloorLayer.GetColour(pipeNode.NodeLocation, pipeNode.RelatedTile);
                itempipe.Setsprite();
                //matrix.RemoveUnderFloorTile(pipeNode.NodeLocation,pipeNode.RelatedTile);
                pipeNode.LocatedOn.RemoveUnderFloorTile(pipeNode.NodeLocation, pipeNode.RelatedTile);

                pipeNode.IsOn.PipeData.Remove(pipeNode);
                this.OnDisable();
            }
        }
예제 #17
0
    /// <summary>
    /// Server:
    /// Allow items to be stored by clicking on bags with item in hand
    /// and clicking items with bag in hand if CanClickPickup is enabled
    ///
    /// </summary>
    public void ServerPerformInteraction(PositionalHandApply interaction)
    {
        // See which item needs to be stored
        if (Validations.IsTarget(gameObject, interaction))
        {
            // Add hand item to this storage
            Inventory.ServerTransfer(interaction.HandSlot, itemStorage.GetBestSlotFor(interaction.HandObject));
        }
        // See if this item can click pickup
        else if (canClickPickup)
        {
            switch (pickupMode)
            {
            case PickupMode.Single:
                // Store the clicked item
                var slot = itemStorage.GetBestSlotFor(interaction.TargetObject);
                if (slot == null)
                {
                    Chat.AddExamineMsgFromServer(interaction.Performer,
                                                 $"The {interaction.TargetObject.ExpensiveName()} doesn't fit!");
                    return;
                }
                Inventory.ServerAdd(interaction.TargetObject, slot);
                break;

            case PickupMode.Same:
                if (interaction.TargetObject == null ||
                    interaction.TargetObject.Item() == null)
                {
                    Chat.AddExamineMsgFromServer(interaction.Performer, "There's nothing to pickup!");
                    return;
                }

                // Get all items of the same type on the tile and try to store them
                var itemsOnTileSame = MatrixManager.GetAt <ItemAttributesV2>(interaction.WorldPositionTarget.To2Int().To3Int(), true);

                if (itemsOnTileSame.Count == 0)
                {
                    Chat.AddExamineMsgFromServer(interaction.Performer, "There's nothing to pickup!");
                    return;
                }

                foreach (var item in itemsOnTileSame)
                {
                    // Only try to add it if it matches the target object's traits
                    if (item.HasAllTraits(interaction.TargetObject.Item().GetTraits()))
                    {
                        // Try to add each item to the storage
                        // Can't break this loop when it fails because some items might not fit and
                        // there might be stacks with space still
                        Inventory.ServerAdd(item.gameObject, itemStorage.GetBestSlotFor(item.gameObject));
                    }
                }
                Chat.AddExamineMsgFromServer(interaction.Performer, $"You put everything you could in the {gameObject.ExpensiveName()}.");
                break;

            case PickupMode.All:
                // Get all items on the tile and try to store them
                var itemsOnTileAll = MatrixManager.GetAt <ItemAttributesV2>(interaction.WorldPositionTarget.To2Int().To3Int(), true);

                if (itemsOnTileAll.Count == 0)
                {
                    Chat.AddExamineMsgFromServer(interaction.Performer, "There's nothing to pickup!");
                    return;
                }

                foreach (var item in itemsOnTileAll)
                {
                    // Try to add each item to the storage
                    // Can't break this loop when it fails because some items might not fit and
                    // there might be stacks with space still
                    Inventory.ServerAdd(item.gameObject, itemStorage.GetBestSlotFor(item.gameObject));
                }
                Chat.AddExamineMsgFromServer(interaction.Performer, $"You put everything you could in the {gameObject.ExpensiveName()}.");
                break;
            }
        }
    }
예제 #18
0
 T GetAtRelative <T>(Orientation orientation) where T : MonoBehaviour
 {
     return(MatrixManager.GetAt <T>(player.ClientPosition + Vector3Int.FloorToInt(orientation.Vector), true).First());
 }
예제 #19
0
    private void PropagateChatToClients(ChatEvent chatEvent)
    {
        List <ConnectedPlayer> players = PlayerList.Instance.AllPlayers;

        //Local chat range checks:
        if (chatEvent.channels.HasFlag(ChatChannel.Local) ||
            chatEvent.channels.HasFlag(ChatChannel.Combat) ||
            chatEvent.channels.HasFlag(ChatChannel.Action))
        {
            for (int i = players.Count - 1; i >= 0; i--)
            {
                if (players[i].Script == null)
                {
                    //joined viewer, don't message them
                    players.RemoveAt(i);
                    continue;
                }

                if (players[i].Script.IsGhost)
                {
                    //send all to ghosts
                    continue;
                }

                if (chatEvent.position == TransformState.HiddenPos)
                {
                    //show messages with no provided position to everyone
                    continue;
                }

                if (Vector2.Distance(chatEvent.position,
                                     (Vector3)players[i].Script.WorldPos) > 14f)
                {
                    //Player in the list is too far away for local chat, remove them:
                    players.RemoveAt(i);
                }
                else
                {
                    //within range, but check if they are in another room or hiding behind a wall
                    if (MatrixManager.Linecast(chatEvent.position, LayerTypeSelection.Walls
                                               , layerMask, (Vector3)players[i].Script.WorldPos).ItHit)
                    {
                        //if it hit a wall remove that player
                        players.RemoveAt(i);
                    }
                }
            }

            //Get NPCs in vicinity
            var npcs = Physics2D.OverlapCircleAll(chatEvent.position, 14f, npcMask);
            foreach (Collider2D coll in npcs)
            {
                if (MatrixManager.Linecast(chatEvent.position, LayerTypeSelection.Walls,
                                           layerMask, coll.transform.position).ItHit == false)
                {
                    //NPC is in hearing range, pass the message on:
                    var mobAi = coll.GetComponent <MobAI>();
                    if (mobAi != null)
                    {
                        mobAi.LocalChatReceived(chatEvent);
                    }
                }
            }
        }

        for (var i = 0; i < players.Count; i++)
        {
            ChatChannel channels = chatEvent.channels;

            if (channels.HasFlag(ChatChannel.Combat) || channels.HasFlag(ChatChannel.Local) ||
                channels.HasFlag(ChatChannel.System) || channels.HasFlag(ChatChannel.Examine) ||
                channels.HasFlag(ChatChannel.Action))
            {
                if (!channels.HasFlag(ChatChannel.Binary) || players[i].Script.IsGhost)
                {
                    UpdateChatMessage.Send(players[i].GameObject, channels, chatEvent.modifiers, chatEvent.message, chatEvent.messageOthers,
                                           chatEvent.originator, chatEvent.speaker);

                    continue;
                }
            }

            if (players[i].Script == null)
            {
                channels &= ChatChannel.OOC;
            }
            else
            {
                channels &= players[i].Script.GetAvailableChannelsMask(false);
            }

            //if the mask ends up being a big fat 0 then don't do anything
            if (channels != ChatChannel.None)
            {
                UpdateChatMessage.Send(players[i].GameObject, channels, chatEvent.modifiers, chatEvent.message, chatEvent.messageOthers,
                                       chatEvent.originator, chatEvent.speaker);
            }
        }

        if (rconManager != null)
        {
            string name = "";
            if ((namelessChannels & chatEvent.channels) != chatEvent.channels)
            {
                name = "<b>[" + chatEvent.channels + "]</b> ";
            }

            RconManager.AddChatLog(name + chatEvent.message);
        }
    }
예제 #20
0
    public void OnHover()
    {
        var wallMount = CheckWallMountOverlay();

        if (wallMount)
        {
            Vector2         cameraPos      = Camera.main.ScreenToWorldPoint(CommonInput.mousePosition);
            var             tilePos        = cameraPos.RoundToInt();
            OrientationEnum orientation    = OrientationEnum.Down;
            Vector3Int      PlaceDirection = PlayerManager.LocalPlayerScript.WorldPos - tilePos;
            bool            isWallBlocked  = false;
            if (PlaceDirection.x != 0 && !MatrixManager.IsWallAtAnyMatrix(tilePos + new Vector3Int(PlaceDirection.x > 0 ? 1 : -1, 0, 0), true))
            {
                if (PlaceDirection.x > 0)
                {
                    orientation = OrientationEnum.Right;
                }
                else
                {
                    orientation = OrientationEnum.Left;
                }
            }
            else
            {
                if (PlaceDirection.y != 0 && !MatrixManager.IsWallAtAnyMatrix(tilePos + new Vector3Int(0, PlaceDirection.y > 0 ? 1 : -1, 0), true))
                {
                    if (PlaceDirection.y > 0)
                    {
                        orientation = OrientationEnum.Up;
                    }
                    else
                    {
                        orientation = OrientationEnum.Down;
                    }
                }
                else
                {
                    isWallBlocked = true;
                }
            }

            if (!MatrixManager.IsWallAtAnyMatrix(tilePos, false) || isWallBlocked)
            {
                if (instanceActive)
                {
                    instanceActive = false;
                    Highlight.DeHighlight();
                }
                return;
            }

            if (!instanceActive)
            {
                instanceActive = true;
                Highlight.ShowHighlight(UIManager.Hands.CurrentSlot.ItemObject, true);
            }

            Vector3 spritePos = tilePos;
            if (wallMount.IsWallProtrusion)             //for light bulbs, tubes, cameras, etc. move the sprite towards the floor
            {
                if (orientation == OrientationEnum.Right)
                {
                    spritePos.x += 0.5f;
                    Highlight.instance.spriteRenderer.transform.rotation = Quaternion.Euler(0, 0, 270);
                }
                else if (orientation == OrientationEnum.Left)
                {
                    spritePos.x -= 0.5f;
                    Highlight.instance.spriteRenderer.transform.rotation = Quaternion.Euler(0, 0, 90);
                }
                else if (orientation == OrientationEnum.Up)
                {
                    spritePos.y += 0.5f;
                    Highlight.instance.spriteRenderer.transform.rotation = Quaternion.Euler(0, 0, 0);
                }
                else
                {
                    spritePos.y -= 0.5f;
                    Highlight.instance.spriteRenderer.transform.rotation = Quaternion.Euler(0, 0, 0);
                }
            }
            Highlight.instance.spriteRenderer.transform.position = spritePos;
        }
    }
예제 #21
0
 void Start()
 {
     MatrixManager.RegisterMatrix(this, IsSpaceMatrix, IsMainStation, IsLavaLand);
 }
예제 #22
0
    /// <summary>
    /// Server:
    /// Allow items to be stored by clicking on bags with item in hand
    /// and clicking items with bag in hand if CanClickPickup is enabled
    ///
    /// </summary>
    public void ServerPerformInteraction(PositionalHandApply interaction)
    {
        if (!allowedToInteract)
        {
            return;
        }
        // See which item needs to be stored
        if (Validations.IsTarget(gameObject, interaction))
        {
            // Add hand item to this storage
            Inventory.ServerTransfer(interaction.HandSlot, itemStorage.GetBestSlotFor(interaction.HandObject));
        }
        // See if this item can click pickup
        else if (canClickPickup)
        {
            bool       pickedUpSomething = false;
            Pickupable pickup;
            switch (pickupMode)
            {
            case PickupMode.Single:

                // Don't pick up items which aren't set as CanPickup
                pickup = interaction.TargetObject.GetComponent <Pickupable>();
                if (pickup == null || pickup.CanPickup == false)
                {
                    Chat.AddExamineMsgFromServer(interaction.Performer, "There's nothing to pickup!");
                    return;
                }

                // Store the clicked item
                var slot = itemStorage.GetBestSlotFor(interaction.TargetObject);
                if (slot == null)
                {
                    Chat.AddExamineMsgFromServer(interaction.Performer,
                                                 $"The {interaction.TargetObject.ExpensiveName()} doesn't fit!");
                    return;
                }

                Inventory.ServerAdd(interaction.TargetObject, slot);
                break;

            case PickupMode.Same:
                if (interaction.TargetObject == null ||
                    interaction.TargetObject.Item() == null)
                {
                    Chat.AddExamineMsgFromServer(interaction.Performer, "There's nothing to pickup!");
                    return;
                }

                // Get all items of the same type on the tile and try to store them
                var itemsOnTileSame =
                    MatrixManager.GetAt <ItemAttributesV2>(interaction.WorldPositionTarget.To2Int().To3Int(), true);

                if (itemsOnTileSame.Count == 0)
                {
                    Chat.AddExamineMsgFromServer(interaction.Performer, "There's nothing to pickup!");
                    return;
                }

                foreach (var item in itemsOnTileSame)
                {
                    // Don't pick up items which aren't set as CanPickup
                    pickup = item.gameObject.GetComponent <Pickupable>();
                    if (pickup == null || pickup.CanPickup == false)
                    {
                        continue;
                    }

                    // Only try to add it if it matches the target object's traits
                    if (item.HasAllTraits(interaction.TargetObject.Item().GetTraits()))
                    {
                        // Try to add each item to the storage
                        // Can't break this loop when it fails because some items might not fit and
                        // there might be stacks with space still
                        if (Inventory.ServerAdd(item.gameObject, itemStorage.GetBestSlotFor(item.gameObject)))
                        {
                            pickedUpSomething = true;
                        }
                    }
                }

                Chat.AddExamineMsgFromServer(interaction.Performer,
                                             $"You put everything you could in the {gameObject.ExpensiveName()}.");
                break;

            case PickupMode.All:
                // Get all items on the tile and try to store them
                var itemsOnTileAll =
                    MatrixManager.GetAt <ItemAttributesV2>(interaction.WorldPositionTarget.To2Int().To3Int(), true);

                if (itemsOnTileAll.Count == 0)
                {
                    Chat.AddExamineMsgFromServer(interaction.Performer, "There's nothing to pickup!");
                    return;
                }

                foreach (var item in itemsOnTileAll)
                {
                    // Don't pick up items which aren't set as CanPickup
                    pickup = item.gameObject.GetComponent <Pickupable>();
                    if (pickup == null || pickup.CanPickup == false)
                    {
                        continue;
                    }

                    // Try to add each item to the storage
                    // Can't break this loop when it fails because some items might not fit and
                    // there might be stacks with space still
                    if (Inventory.ServerAdd(item.gameObject, itemStorage.GetBestSlotFor(item.gameObject)))
                    {
                        pickedUpSomething = true;
                    }
                }

                if (pickedUpSomething)
                {
                    Chat.AddExamineMsgFromServer(interaction.Performer,
                                                 $"You put everything you could in the {gameObject.ExpensiveName()}.");
                }
                else
                {
                    Chat.AddExamineMsgFromServer(interaction.Performer, "There's nothing to pickup!");
                }

                break;

            case PickupMode.DropClick:
                if (canQuickEmpty)
                {
                    // Drop all items that are inside this storage
                    var slots = itemStorage.GetItemSlots();
                    if (slots == null)
                    {
                        Chat.AddExamineMsgFromServer(interaction.Performer, "It's already empty!");


                        return;
                    }
                    if (PlayerManager.PlayerScript == null)
                    {
                        return;
                    }
                    if (Validations.IsInReachDistanceByPositions(PlayerManager.PlayerScript.registerTile.WorldPosition, interaction.WorldPositionTarget) == false)
                    {
                        return;
                    }
                    if (MatrixManager.IsPassableAtAllMatricesOneTile(interaction.WorldPositionTarget.RoundToInt(), CustomNetworkManager.Instance._isServer) == false)
                    {
                        return;
                    }

                    PlayerManager.PlayerScript.playerNetworkActions.CmdDropAllItems(itemStorage.GetIndexedItemSlot(0)
                                                                                    .ItemStorageNetID, interaction.WorldPositionTarget);


                    Chat.AddExamineMsgFromServer(interaction.Performer, $"You start dumping out the {gameObject.ExpensiveName()}.");
                }

                break;
            }
        }
    }
    private bool CheckFloatingServer(Vector3 goal)
    {
        bool isRecursive = goal != TransformState.HiddenPos;

        if (!IsFloatingServer || matrix == null)
        {
            return(isRecursive);
        }

        Vector3 worldPosition = serverState.WorldPosition;
        Vector3 moveDelta;

        if (!isRecursive)
        {         //Normal delta if not recursive
            moveDelta = (Vector3)serverState.WorldImpulse * serverState.Speed * Time.deltaTime;
        }
        else
        {         //Artificial delta if recursive
            moveDelta = goal - worldPosition;
        }

        Vector3Int intOrigin = Vector3Int.RoundToInt(worldPosition);

        if (intOrigin.x > 18000 || intOrigin.x < -18000 || intOrigin.y > 18000 || intOrigin.y < -18000)
        {
            Stop();
            Logger.Log($"ITEM {transform.name} was forced to stop at {intOrigin}", Category.Movement);
            return(true);
        }

        float   distance = moveDelta.magnitude;
        Vector3 newGoal;

        if (distance > 1)
        {
            //limit goal to just one tile away and run this method recursively afterwards
            newGoal = worldPosition + (Vector3)serverState.WorldImpulse;
        }
        else
        {
            newGoal = worldPosition + moveDelta;
        }
        Vector3Int intGoal = Vector3Int.RoundToInt(newGoal);

        bool isWithinTile = intOrigin == intGoal;         //same tile, no need to validate stuff

        if (isWithinTile || ValidateFloating(worldPosition, newGoal))
        {
            AdvanceMovement(worldPosition, newGoal);
        }
        else
        {
            if (serverState.Speed >= PushPull.HIGH_SPEED_COLLISION_THRESHOLD && IsTileSnap)
            {
                //Stop first (reach tile), then inform about collision
                var collisionInfo = new CollisionInfo
                {
                    Speed         = serverState.Speed,
                    Size          = this.Size,
                    CollisionTile = intGoal
                };

                Stop();

                OnHighSpeedCollision().Invoke(collisionInfo);
            }
            else
            {
                Stop();
            }

            //Process any objects that we might have bumped into
            foreach (var objectBehaviour in MatrixManager.GetAt <ObjectBehaviour>(intGoal, true))
            {
                foreach (var bump in objectBehaviour.GetComponents <IBumpableObject>())
                {
                    bump.OnBump(gameObject);
                }
            }
        }

        if (distance > 1)
        {
            CheckFloatingServer(isRecursive ? goal : newGoal);
        }

        return(true);
    }
예제 #24
0
    private void Update()
    {
        if (state == State.SELECTING)
        {
            // ignore when we are over UI
            if (EventSystem.current.IsPointerOverGameObject())
            {
                return;
            }

            //check which objects we are over, pick the top one to spawn
            if (CommonInput.GetMouseButtonDown(0))
            {
                //NOTE: Avoiding multiple enumeration by converting IEnumerables to lists.
                var hitGOs = MouseUtils.GetOrderedObjectsUnderMouse(layerMask,
                                                                    go => go.GetComponent <CustomNetTransform>() != null)
                             .Select(r => r.GetComponentInParent <CustomNetTransform>().gameObject).ToList();
                //warn about objects which cannot be cloned
                var nonPooledHits = hitGOs
                                    .Where(go => PoolManager.DeterminePrefab(go) == null).ToList();
                if (nonPooledHits.Any())
                {
                    foreach (GameObject nonPooled in nonPooledHits)
                    {
                        Logger.LogWarningFormat("Object {0} does not have a PoolPrefabTracker component and its name" +
                                                " did not match one of our existing prefabs " +
                                                "therefore cannot be cloned (because we wouldn't know which prefab to instantiate). " +
                                                "Please attach this component to the object and specify the prefab" +
                                                " to allow it to be cloned.", Category.ItemSpawn, nonPooled.name);
                    }
                }

                var pooledHits = hitGOs.Where(go => PoolManager.DeterminePrefab(go) != null).ToList();
                if (pooledHits.Any())
                {
                    toClone = pooledHits.First();
                    ToState(State.DRAWING);
                }
            }
        }
        else if (state == State.DRAWING)
        {
            cursorObject.transform.position = Camera.main.ScreenToWorldPoint(CommonInput.mousePosition);
            if (CommonInput.GetMouseButtonDown(0))
            {
                Vector3Int position = cursorObject.transform.position.RoundToInt();
                position.z = 0;
                if (MatrixManager.IsPassableAt(position))
                {
                    if (CustomNetworkManager.IsServer)
                    {
                        PoolManager.NetworkClone(toClone, position);
                    }
                    else
                    {
                        DevCloneMessage.Send(toClone, (Vector3)position);
                    }
                }
            }
        }
    }
예제 #25
0
    private PlayerState NextStateServer(PlayerState state, PlayerAction action)
    {
        bool isServerBump = !CanMoveThere(state, action);
        bool isClientBump = action.isBump;

        if (!isClientBump && isServerBump)
        {
            Logger.LogWarningFormat("isBump mismatch, resetting: C={0} S={1}", Category.Movement, isClientBump, isServerBump);
            RollbackPosition();
        }
        if (isClientBump || isServerBump)
        {
            //gotta try pushing things
            BumpInteract(state.WorldPosition, (Vector2)action.Direction());

            playerSprites.FaceDirection(Orientation.From(action.Direction()));
            return(state);
        }

        if (IsNonStickyServer)
        {
            PushPull pushable;
            if (IsAroundPushables(serverState, out pushable))
            {
                StartCoroutine(InteractSpacePushable(pushable, action.Direction()));
            }
            return(state);
        }

        if (action.isNonPredictive)
        {
            Logger.Log("Ignored action marked as Non-predictive while being indoors", Category.Movement);
            return(state);
        }

        bool        matrixChangeDetected;
        PlayerState nextState = NextState(state, action, out matrixChangeDetected);

        if (!matrixChangeDetected)
        {
            return(nextState);
        }

        //todo: subscribe to current matrix rotations on spawn
        var newMatrix = MatrixManager.Get(nextState.MatrixId);

        Logger.Log($"Matrix will change to {newMatrix}", Category.Movement);
        if (newMatrix.MatrixMove)
        {
            //Subbing to new matrix rotations
            newMatrix.MatrixMove.OnRotate.AddListener(OnRotation);
            //				Logger.Log( $"Registered rotation listener to {newMatrix.MatrixMove}" );
        }

        //Unsubbing from old matrix rotations
        MatrixMove oldMatrixMove = MatrixManager.Get(matrix).MatrixMove;

        if (oldMatrixMove)
        {
            //				Logger.Log( $"Unregistered rotation listener from {oldMatrixMove}" );
            oldMatrixMove.OnRotate.RemoveListener(OnRotation);
        }

        return(nextState);
    }
예제 #26
0
 /// Same as ExposeHotspot but allows providing a world position and handles the conversion
 public void ExposeHotspotWorldPosition(Vector2Int tileWorldPosition)
 {
     ExposeHotspot(MatrixManager.WorldToLocalInt(tileWorldPosition.To3Int(), MatrixManager.Get(matrix)));
 }
예제 #27
0
    private void Expose(Vector3Int hotspotPosition, Vector3Int atLocalPosition)
    {
        var isSideExposure = hotspotPosition != atLocalPosition;
        //calculate world position
        var hotspotWorldPosition = MatrixManager.LocalToWorldInt(hotspotPosition, MatrixManager.Get(matrix));
        var atWorldPosition      = MatrixManager.LocalToWorldInt(atLocalPosition, MatrixManager.Get(matrix));

        if (!hotspots.ContainsKey(hotspotPosition))
        {
            Logger.LogError("Hotspot position key was not found in the hotspots dictionary", Category.Atmos);
            return;
        }

        var exposure = FireExposure.FromMetaDataNode(hotspots[hotspotPosition], hotspotWorldPosition.To2Int(), atLocalPosition.To2Int(), atWorldPosition.To2Int());

        if (isSideExposure)
        {
            //side exposure logic

            //already exposed by a different hotspot
            if (hotspots.ContainsKey(atLocalPosition))
            {
                return;
            }

            var metadata = metaDataLayer.Get(atLocalPosition);
            if (!metadata.IsOccupied)
            {
                //atmos can pass here, so no need to check side exposure (nothing to brush up against)
                return;
            }

            //only expose to atmos impassable objects, since those are the things the flames would
            //actually brush up against
            var regTiles = matrix.Get <RegisterTile>(atLocalPosition, true);
            foreach (var regTile in regTiles)
            {
                if (!regTile.IsAtmosPassable(exposure.HotspotLocalPosition.To3Int(), true))
                {
                    var exposable = regTile.GetComponent <IFireExposable>();
                    exposable.OnExposed(exposure);
                }
            }

            //expose the tiles there
            foreach (var tilemapDamage in tilemapDamages)
            {
                tilemapDamage.OnExposed(exposure);
            }
        }
        else
        {
            //direct exposure logic
            var fireExposables = matrix.Get <IFireExposable>(atLocalPosition, true);
            foreach (var exposable in fireExposables)
            {
                exposable.OnExposed(exposure);
            }
            //expose the tiles
            foreach (var tilemapDamage in tilemapDamages)
            {
                tilemapDamage.OnExposed(exposure);
            }
        }
    }
예제 #28
0
        private void Expose(Vector3Int hotspotPosition, Vector3Int atLocalPosition)
        {
            Profiler.BeginSample("ExposureInit");
            var isSideExposure = hotspotPosition != atLocalPosition;
            //calculate world position
            var hotspotWorldPosition = MatrixManager.LocalToWorldInt(hotspotPosition, MatrixManager.Get(matrix));
            var atWorldPosition      = MatrixManager.LocalToWorldInt(atLocalPosition, MatrixManager.Get(matrix));

            if (!hotspots.ContainsKey(hotspotPosition))
            {
                Logger.LogError("Hotspot position key was not found in the hotspots dictionary", Category.Atmos);
                return;
            }


            //update fire exposure, reusing it to avoid creating GC.
            applyExposure.Update(isSideExposure, hotspots[hotspotPosition], hotspotWorldPosition, atLocalPosition,
                                 atWorldPosition);
            Profiler.EndSample();
            if (isSideExposure)
            {
                Profiler.BeginSample("SideExposure");
                //side exposure logic

                //already exposed by a different hotspot
                if (hotspots.ContainsKey(atLocalPosition))
                {
                    Profiler.EndSample();
                    return;
                }

                var metadata = metaDataLayer.Get(atLocalPosition);
                if (!metadata.IsOccupied)
                {
                    //atmos can pass here, so no need to check side exposure (nothing to brush up against)
                    Profiler.EndSample();
                    return;
                }

                //only expose to atmos impassable objects, since those are the things the flames would
                //actually brush up against
                matrix.ServerObjects.InvokeOnObjects(applyExposure, atLocalPosition);
                //expose the tiles there
                foreach (var tilemapDamage in tilemapDamages)
                {
                    tilemapDamage.OnExposed(applyExposure.FireExposure);
                }

                Profiler.EndSample();
            }
            else
            {
                Profiler.BeginSample("DirectExposure");
                //direct exposure logic
                matrix.ServerObjects.InvokeOnObjects(applyExposure, atLocalPosition);
                //expose the tiles
                foreach (var tilemapDamage in tilemapDamages)
                {
                    tilemapDamage.OnExposed(applyExposure.FireExposure);
                }

                Profiler.EndSample();
            }
        }
예제 #29
0
        public override void Process(NetMessage msg)
        {
            var clientStorage = SentByPlayer.Script.DynamicItemStorage;
            var usedSlot      = clientStorage.GetActiveHandSlot();

            if (usedSlot == null || usedSlot.ItemObject == null)
            {
                return;
            }

            var hasConstructionMenu = usedSlot.ItemObject.GetComponent <BuildingMaterial>();

            if (hasConstructionMenu == null)
            {
                return;
            }

            var entry = hasConstructionMenu.BuildList.Entries.ToArray()[msg.EntryIndex];

            if (!entry.CanBuildWith(hasConstructionMenu))
            {
                return;
            }

            //check if the space to construct on is passable
            if (!MatrixManager.IsPassableAtAllMatricesOneTile((Vector3Int)SentByPlayer.GameObject.TileWorldPosition(), true, includingPlayers: false))
            {
                Chat.AddExamineMsg(SentByPlayer.GameObject, "It won't fit here.");
                return;
            }

            //if we are building something impassable, check if there is anything on the space other than the performer.
            var atPosition =
                MatrixManager.GetAt <RegisterTile>((Vector3Int)SentByPlayer.GameObject.TileWorldPosition(), true);

            if (entry.Prefab == null)
            {
                //requires immediate attention, show it regardless of log filter:
                Logger.Log($"Construction entry is missing prefab for {entry.Name}", Category.Construction);
                return;
            }

            var registerTile = entry.Prefab.GetComponent <RegisterTile>();

            if (registerTile == null)
            {
                Logger.LogWarningFormat("Buildable prefab {0} has no registerTile, no idea if it's passable", Category.Construction, entry.Prefab);
            }
            var builtObjectIsImpassable = registerTile == null || !registerTile.IsPassable(true);

            foreach (var thingAtPosition in atPosition)
            {
                if (entry.OnePerTile)
                {
                    //can only build one of this on a given tile
                    if (entry.Prefab.Equals(Spawn.DeterminePrefab(thingAtPosition.gameObject)))
                    {
                        Chat.AddExamineMsg(SentByPlayer.GameObject, $"There's already one here.");
                        return;
                    }
                }

                if (builtObjectIsImpassable)
                {
                    //if the object we are building is itself impassable, we should check if anything blocks construciton.
                    //otherwise it's fine to add it to the pile on the tile
                    if (ServerValidations.IsConstructionBlocked(SentByPlayer.GameObject, null,
                                                                SentByPlayer.GameObject.TileWorldPosition()))
                    {
                        return;
                    }
                }
            }

            //build and consume
            void ProgressComplete()
            {
                var spawnedObj = entry.ServerBuild(SpawnDestination.At(SentByPlayer.Script.registerTile), hasConstructionMenu);

                if (spawnedObj)
                {
                    var conveyorBelt = spawnedObj.GetComponent <ConveyorBelt>();
                    if (conveyorBelt != null)
                    {
                        conveyorBelt.SetBeltFromBuildMenu(msg.Direction);
                    }

                    Chat.AddActionMsgToChat(SentByPlayer.GameObject, $"You finish building the {entry.Name}.",
                                            $"{SentByPlayer.GameObject.ExpensiveName()} finishes building the {entry.Name}.");
                }
            }

            Chat.AddActionMsgToChat(SentByPlayer.GameObject, $"You begin building the {entry.Name}...",
                                    $"{SentByPlayer.GameObject.ExpensiveName()} begins building the {entry.Name}...");
            ToolUtils.ServerUseTool(SentByPlayer.GameObject, usedSlot.ItemObject,
                                    ActionTarget.Tile(SentByPlayer.Script.registerTile.WorldPositionServer), entry.BuildTime,
                                    ProgressComplete);
        }
예제 #30
0
        public void ServerPerformInteraction(HandApply interaction)
        {
            if (interaction.TargetObject != gameObject)
            {
                return;
            }

            if (Validations.HasItemTrait(interaction.HandObject, CommonTraits.Instance.MetalSheet))
            {
                if (objectBehaviour.IsPushable)
                {
                    if (!Validations.HasAtLeast(interaction.HandObject, 2))
                    {
                        Chat.AddExamineMsg(interaction.Performer, "You need two sheets of metal to finish a false wall!");
                        return;
                    }
                    ToolUtils.ServerUseToolWithActionMessages(interaction, 4f,
                                                              "You start adding plating...",
                                                              $"{interaction.Performer.ExpensiveName()} begins adding plating...",
                                                              "You create a false wall.",
                                                              $"{interaction.Performer.ExpensiveName()} creates a false wall.",
                                                              () => ConstructFalseWall(interaction));
                }
                else
                {
                    if (!Validations.HasAtLeast(interaction.HandObject, 2))
                    {
                        Chat.AddExamineMsg(interaction.Performer, "You need two sheets of metal to finish a wall!");
                        return;
                    }
                    ToolUtils.ServerUseToolWithActionMessages(interaction, 4f,
                                                              "You start adding plating...",
                                                              $"{interaction.Performer.ExpensiveName()} begins adding plating...",
                                                              "You create a wall.",
                                                              $"{interaction.Performer.ExpensiveName()} creates a wall.",
                                                              () => ConstructWall(interaction));
                }
            }
            else if (Validations.HasItemTrait(interaction.HandObject, CommonTraits.Instance.PlasteelSheet))
            {
                if (objectBehaviour.IsPushable)
                {
                    if (!Validations.HasAtLeast(interaction.HandObject, 2))
                    {
                        Chat.AddExamineMsg(interaction.Performer, "You need at least two sheets to create a reinforced false wall!");
                        return;
                    }
                    ToolUtils.ServerUseToolWithActionMessages(interaction, 4f,
                                                              "You start adding plating...",
                                                              $"{interaction.Performer.ExpensiveName()} begins adding plating...",
                                                              "You add the plating.",
                                                              $"{interaction.Performer.ExpensiveName()} adds the plating.",
                                                              () => ConstructReinforcedFalseWall(interaction));
                }
                else
                {
                    //add plasteel for constructing reinforced girder
                    ToolUtils.ServerUseToolWithActionMessages(interaction, 6f,
                                                              "You start reinforcing the girder...",
                                                              $"{interaction.Performer.ExpensiveName()} starts reinforcing the girder...",
                                                              "You reinforce the girder.",
                                                              $"{interaction.Performer.ExpensiveName()} reinforces the girder.",
                                                              () => ReinforceGirder(interaction));
                }
            }
            else if (Validations.HasItemTrait(interaction.HandObject, CommonTraits.Instance.Wrench))
            {
                if (objectBehaviour.IsPushable)
                {
                    //secure it if there's floor
                    if (MatrixManager.IsSpaceAt(registerObject.WorldPositionServer, true))
                    {
                        Chat.AddExamineMsg(interaction.Performer, "A floor must be present to secure the girder!");
                        return;
                    }

                    if (!ServerValidations.IsAnchorBlocked(interaction))
                    {
                        ToolUtils.ServerUseToolWithActionMessages(interaction, 4f,
                                                                  "You start securing the girder...",
                                                                  $"{interaction.Performer.ExpensiveName()} starts securing the girder...",
                                                                  "You secure the girder.",
                                                                  $"{interaction.Performer.ExpensiveName()} secures the girder.",
                                                                  () => objectBehaviour.ServerSetAnchored(true, interaction.Performer));
                    }
                }
                else
                {
                    //unsecure it
                    ToolUtils.ServerUseToolWithActionMessages(interaction, 4f,
                                                              "You start unsecuring the girder...",
                                                              $"{interaction.Performer.ExpensiveName()} starts unsecuring the girder...",
                                                              "You unsecure the girder.",
                                                              $"{interaction.Performer.ExpensiveName()} unsecures the girder.",
                                                              () => objectBehaviour.ServerSetAnchored(false, interaction.Performer));
                }
            }
            else if (Validations.HasItemTrait(interaction.HandObject, CommonTraits.Instance.Screwdriver))
            {
                //disassemble if it's unanchored
                if (objectBehaviour.IsPushable)
                {
                    ToolUtils.ServerUseToolWithActionMessages(interaction, 4f,
                                                              "You start to disassemble the girder...",
                                                              $"{interaction.Performer.ExpensiveName()} starts to disassemble the girder...",
                                                              "You disassemble the girder.",
                                                              $"{interaction.Performer.ExpensiveName()} disassembles the girder.",
                                                              () => Disassemble(interaction));
                }
                else
                {
                    Chat.AddExamineMsg(interaction.Performer, "You must unsecure it first.");
                }
            }
        }