Example #1
0
        public void TakeDamage(int damage, long?damagerID = null)
        {
            if (ModEntry.BRGame.IsGameInProgress)
            {
                dummyMonster = dummyMonster ?? new StardewValley.Monsters.Monster();

                try
                {
                    bool oldIsEating = Game1.player.isEating;
                    Game1.player.isEating = false;                        //Prevent invincibility

                    Game1.player.takeDamage(damage, false, dummyMonster); //If you pass in null as monster the player won't take damage

                    Game1.player.isEating = oldIsEating;
                }catch (Exception)
                {
                    Console.WriteLine("Ignoring exception in takeDamage");
                }

                Farmer damager = null;
                if (Game1.currentLocation != null && Game1.currentLocation.farmers != null)
                {
                    foreach (Farmer player in Game1.currentLocation?.farmers)
                    {
                        //Hit shake timer / Invincibility frames
                        if (player != Game1.player && player != null)
                        {
                            var objects = new object[] { (int)NetworkUtility.MessageTypes.TELL_PLAYER_HIT_SHAKE_TIMER, 1200 };                            //Hard coded in Farmer.MovePosition
                            if (Game1.IsServer)
                            {
                                Game1.server.sendMessage(player.UniqueMultiplayerID, new OutgoingMessage(NetworkUtility.uniqueMessageType, Game1.player, objects));
                            }
                            else
                            {
                                NetworkUtility.RelayMessageFromClientToAnotherPlayer(player.UniqueMultiplayerID, objects);
                            }

                            if (player.UniqueMultiplayerID == damagerID)
                            {
                                damager = player;
                            }
                        }
                    }
                }

                //Knockback (knock the player)
                if (damager != null && damage > 0 && (DateTime.Now - knockbackImmunityTimeActivated).TotalMilliseconds >= knockbackImmunityMilliseconds)
                {
                    double amount = 10 + 8 * (-1 + 2 / (1 + Math.Pow(Math.E, -0.03 * damage)));
                    amount = Math.Min(18, amount);                    //Just in case

                    Vector2 displacement = Vector2.Subtract(Game1.player.Position, damager.Position);
                    if (displacement.LengthSquared() != 0)
                    {
                        displacement.Normalize();

                        displacement.Y = displacement.Y * -1;
                        displacement   = Vector2.Multiply(displacement, (float)amount);

                        Console.WriteLine($"setting trajectory to {displacement.X},{displacement.Y}");

                        Game1.player.setTrajectory((int)displacement.X, (int)displacement.Y);
                    }
                }

                if (Game1.player.health <= 0)
                {
                    //They are dead now
                    Console.WriteLine($"I AM DEAD!");

                    Random random = new Random();

                    //Spawn their items onto the floor
                    foreach (var item in Game1.player.Items)
                    {
                        if (item != null)
                        {
                            if (!(item is Tool) || item is StardewValley.Tools.MeleeWeapon || item is StardewValley.Tools.Slingshot)
                            {
                                Debris debris = new Debris(item, Game1.player.getStandingPosition(), Game1.player.getStandingPosition() + new Microsoft.Xna.Framework.Vector2(64 * (float)(random.NextDouble() * 2 - 1), 64 * (float)(random.NextDouble() * 2 - 1)));
                                Game1.currentLocation.debris.Add(debris);
                            }
                        }
                    }



                    var oldLocation = Game1.player.currentLocation;
                    var oldPosition = new xTile.Dimensions.Location(
                        (int)Game1.player.Position.X - Game1.viewport.Width / 2,
                        (int)Game1.player.Position.Y - Game1.viewport.Height / 2);

                    Game1.player.clearBackpack();
                    Game1.player.health = maxHealth;                    //Otherwise they will go the the Doctor on the next update tick
                    //Game1.player.warpFarmer(new TileLocation("Forest", 100, 20).CreateWarp());//Marnie's cow pen

                    SpectatorMode.EnterSpectatorMode(oldLocation, oldPosition);

                    if (Game1.IsServer)
                    {
                        ModEntry.BRGame.HandleDeath(Game1.player, damagerID);
                    }
                    else
                    {
                        if (damagerID.HasValue)
                        {
                            Game1.client.sendMessage(new OutgoingMessage(NetworkUtility.uniqueMessageType, Game1.player,
                                                                         (int)NetworkUtility.MessageTypes.TELL_SERVER_I_DIED, Game1.player.UniqueMultiplayerID, damagerID.Value));
                        }
                        else
                        {
                            Game1.client.sendMessage(new OutgoingMessage(NetworkUtility.uniqueMessageType, Game1.player,
                                                                         (int)NetworkUtility.MessageTypes.TELL_SERVER_I_DIED, Game1.player.UniqueMultiplayerID));
                        }
                    }
                }
            }
        }
        private static bool ProcessMessage(byte[] msgData, Farmer sourceFarmer)
        {
            var subMessageType = (NetworkUtility.MessageTypes)BitConverter.ToInt32(msgData, 0);

            Console.WriteLine($"Receiving special message, type = {subMessageType}. Message length = {msgData.Length}");

            switch (subMessageType)
            {
            case (NetworkUtility.MessageTypes.TAKE_DAMAGE):
                int damage = BitConverter.ToInt32(msgData, 4);

                long?damagerID = null;
                if (msgData.Length > 8)
                {
                    damagerID = BitConverter.ToInt64(msgData, 8);
                }

                Console.WriteLine($"Taking {damage} damage from another player");

                ModEntry.BRGame.TakeDamage(damage, damagerID);
                return(false);

            case (NetworkUtility.MessageTypes.SERVER_BROADCAST_GAME_START):
                if (!Game1.IsServer)
                {
                    int  numberOfPlayers     = BitConverter.ToInt32(msgData, 4);
                    int  stormIndex          = BitConverter.ToInt32(msgData, 8);
                    bool isHostParticipating = BitConverter.ToBoolean(msgData, 12);

                    ModEntry.BRGame.ClientStartGame(numberOfPlayers, isHostParticipating, stormIndex);
                }
                return(false);

            case NetworkUtility.MessageTypes.WARP:
                int tileX = BitConverter.ToInt32(msgData, 4);
                int tileY = BitConverter.ToInt32(msgData, 8);

                StringBuilder sb = new StringBuilder();
                for (int i = 12; i < msgData.Length; i++)
                {
                    sb.Append((char)msgData[i]);
                }

                string locationName = sb.ToString().Substring(1);

                Console.WriteLine($"I was told by the server to move to {locationName} @ ({tileX},{tileY})");

                //Face downwards & Warp
                Game1.player.FacingDirection = 2;
                Game1.player.warpFarmer(new TileLocation(locationName, tileX, tileY).CreateWarp());
                return(false);

            case (NetworkUtility.MessageTypes.SERVER_BROADCAST_GAME_END):
                if (!Game1.IsServer)
                {
                    ModEntry.BRGame.ClientEndGame();
                }
                return(false);

            case (NetworkUtility.MessageTypes.RELAY_MESSAGE_TO_ANOTHER_PLAYER):
                if (Game1.IsServer)
                {
                    long targetUniqueID = BitConverter.ToInt64(msgData, 4);

                    byte[] messageData = new byte[msgData.Length - 12];
                    Array.Copy(msgData, 12, messageData, 0, msgData.Length - 12);

                    if (targetUniqueID == Game1.player.UniqueMultiplayerID)
                    {
                        Console.WriteLine("Received relay instruction addressed to myself");
                        ProcessMessage(messageData, sourceFarmer);
                        return(false);
                    }
                    else
                    {
                        Console.WriteLine($"Relaying a message to {targetUniqueID}...");
                        Game1.server.sendMessage(targetUniqueID, new OutgoingMessage(NetworkUtility.uniqueMessageType, Game1.player, (object)messageData));
                        return(false);
                    }
                }
                else
                {
                    Console.WriteLine("Accidentally received relay instruction as a client");
                    return(false);
                }

            case (NetworkUtility.MessageTypes.TELL_SERVER_I_DIED):
                if (msgData.Length > 12)
                {
                    ModEntry.BRGame.HandleDeath(sourceFarmer, BitConverter.ToInt64(msgData, 12));
                }
                else
                {
                    ModEntry.BRGame.HandleDeath(sourceFarmer);
                }
                return(false);

            case NetworkUtility.MessageTypes.SERVER_BROADCAST_CHAT_MESSAGE:
                string message   = Encoding.UTF8.GetString(msgData.Skip(4).ToArray()).Substring(1);
                string colorName = "white";
                try
                {
                    colorName = message.Substring(1, message.Substring(1).IndexOf(']'));
                    Console.WriteLine($"color = {colorName}");
                }
                catch (Exception) { }

                var color = StardewValley.Menus.ChatMessage.getColorFromName(colorName);
                if (color == Microsoft.Xna.Framework.Color.White)
                {
                    color = Microsoft.Xna.Framework.Color.Gold;
                }

                Game1.chatBox.addMessage(message, color);
                return(false);

            case (NetworkUtility.MessageTypes.TELL_PLAYER_HIT_SHAKE_TIMER):
                int howLongMilliseconds = BitConverter.ToInt32(msgData, 4);
                HitShaker.SetHitShakeTimer(sourceFarmer.UniqueMultiplayerID, howLongMilliseconds);
                return(false);

            case NetworkUtility.MessageTypes.BROADCAST_ALIVE_COUNT:
                int howManyPlayersAlive = BitConverter.ToInt32(msgData, 4);

                if (ModEntry.BRGame.OverlayUI != null)
                {
                    ModEntry.BRGame.OverlayUI.AlivePlayers = howManyPlayersAlive;
                }
                return(false);

            case NetworkUtility.MessageTypes.SEND_PHASE_DATA:
                try
                {
                    var b = new BinaryFormatter();

                    var phases = (List <Phase>[])b.Deserialize(new MemoryStream(msgData.Skip(4).ToArray()));

                    Console.WriteLine($"Received phases data from server, info: Length={phases.Length}");

                    Storm.Phases = phases;
                }catch (Exception)
                {
                    Console.WriteLine("Unable to process phases data. Kicking to prevent glitches...");
                    long id = sourceFarmer.UniqueMultiplayerID;
                    NetworkUtility.SendChatMessageToPlayerWithoutMod(id, "Unable to process phases data. Kicking to prevent glitches...");
                    Game1.server.sendMessage(id, new OutgoingMessage((byte)19, id, new object[0]));
                    Game1.server.playerDisconnected(id);
                    Game1.otherFarmers.Remove(id);
                }
                return(false);

            case NetworkUtility.MessageTypes.KICK_PLAYER:
                StringBuilder sb2 = new StringBuilder();
                for (int i = 4; i < msgData.Length; i++)
                {
                    sb2.Append((char)msgData[i]);
                }

                string kickMsg = sb2.ToString().Substring(1);
                Console.WriteLine($"Kicked. Reason: \"{kickMsg}\"");

                Game1.client.disconnect();

                System.Threading.Tasks.Task.Factory.StartNew(() =>
                {
                    System.Threading.Thread.Sleep(300);
                    Game1.activeClickableMenu = new StardewValley.Menus.DialogueBox($"Kicked. Reason: \"{kickMsg}\"");
                });

                return(false);

            case NetworkUtility.MessageTypes.SEND_MY_VERSION_TO_SERVER:
                if (Game1.IsServer)
                {
                    int    major = BitConverter.ToInt32(msgData, 4);
                    int    minor = BitConverter.ToInt32(msgData, 8);
                    byte[] sha   = msgData.Skip(12).ToArray();

                    Console.WriteLine($"Received version from client {sourceFarmer.Name}/{sourceFarmer.UniqueMultiplayerID}: {major}.{minor}");
                    new AutoKicker().AcknowledgeClientVersion(sourceFarmer.UniqueMultiplayerID, major, minor, sha);

                    if (ModEntry.BRGame.IsGameInProgress)
                    {
                        System.Threading.Tasks.Task.Factory.StartNew(() =>
                        {
                            System.Threading.Thread.Sleep(1000);
                            Game1.server.sendMessage(sourceFarmer.UniqueMultiplayerID,
                                                     new OutgoingMessage(NetworkUtility.uniqueMessageType, Game1.player, (int)NetworkUtility.MessageTypes.TELL_NEW_PLAYER_TO_SPECTATE));
                        });
                    }
                }
                return(false);

            case NetworkUtility.MessageTypes.TELL_NEW_PLAYER_TO_SPECTATE:
                if (!Game1.IsServer)
                {
                    System.Threading.Tasks.Task.Factory.StartNew(() =>
                    {
                        System.Threading.Thread.Sleep(1000);

                        if (!ModEntry.BRGame.alivePlayers.Contains(Game1.player.UniqueMultiplayerID))
                        {
                            var oldLocation = Game1.player.currentLocation;
                            var oldPosition = new xTile.Dimensions.Location(
                                (int)Game1.player.Position.X - Game1.viewport.Width / 2,
                                (int)Game1.player.Position.Y - Game1.viewport.Height / 2);

                            SpectatorMode.EnterSpectatorMode(oldLocation, oldPosition);
                        }
                    });
                }
                return(false);

            case NetworkUtility.MessageTypes.GIVE_HAT:
                int hatID = 10;                        //Chicken hat
                Game1.player?.addItemToInventory(new StardewValley.Objects.Hat(hatID));
                return(false);

            default:
                return(true);
            }
        }