public static bool Prefix(ref LocationRequest locationRequest, ref int tileX, ref int tileY)
        {
            Console.WriteLine($"warpFarmer called to {locationRequest?.Location.Name ?? "<NULL>"}");
            SpectatorMode.OnWarped(locationRequest);
            ModEntry.BRGame.AddKnockbackImmunity();

            if (!SpectatorMode.InSpectatorMode)
            {
                if (locationRequest.Location.Name == "Tunnel")
                {
                    var m = Game1.player.mount;
                    Game1.player.mount = null;
                    Game1.warpFarmer("Desert", 10000, 45, false);



                    Game1.player.canMove = false;
                    System.Threading.Tasks.Task.Factory.StartNew(() =>
                    {
                        System.Threading.Thread.Sleep(1000);
                        Game1.player.position.X = 46.5f * Game1.tileSize;
                        Game1.player.position.Y = 27 * Game1.tileSize;
                        Game1.player.canMove    = true;

                        m.position.X       = Game1.player.Position.X;
                        m.position.Y       = Game1.player.Position.Y;
                        Game1.player.mount = m;
                    });

                    return(false);
                }
            }

            return(true);
        }
Пример #2
0
        public static bool Prefix(MapPage __instance, int x, int y)
        {
            foreach (var point in __instance.points)
            {
                if (point.containsPoint(x, y))
                {
                    bool r = SpectatorMode.OnClickMapPoint(point);
                    if (!r)
                    {
                        Game1.activeClickableMenu.exitThisMenu(false);
                    }
                    return(r);
                }
            }

            return(true);
        }
Пример #3
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));
                        }
                    }
                }
            }
        }
Пример #4
0
        public override void Entry(IModHelper helper)
        {
            Events = helper.Events;

            if (AntiCheat.HasIllegalMods())
            {
                Game1.quit = true;

                Console.Clear();
                Monitor.Log("You have an illegal mod installed. Please uninstall it before using this mod.", LogLevel.Warn);
                if (AntiCheat.IllegalMod != null)
                {
                    Monitor.Log($"- '{AntiCheat.IllegalMod}'", LogLevel.Warn);
                }
                Monitor.Log("Press any key to continue...", LogLevel.Warn);
                Console.ReadKey();
                return;
            }

            var config = helper.ReadConfig <ModConfig>();

            if (config == null)
            {
                config = new ModConfig();
                helper.WriteConfig(config);
            }

            Config = config;

            BRGame = new Game(helper, config);

            Patch.PatchAll("ilyaki.battleroyale");

            try
            {
                //Remove player limit
                var multiplayer = helper.Reflection.GetField <Multiplayer>(typeof(Game1), "multiplayer").GetValue();
                multiplayer.playerLimit = config.PlayerLimit;//250 is the Galaxy limit (it's multiplied by two for some reason, so set 125)
            }catch (Exception)
            {
                Monitor.Log("Error setting player limit. The max is 125", LogLevel.Error);
            }


            helper.ConsoleCommands.Add("br_start", "Start the game. Alternative to pressing Right control", (c, a) => {
                if (Game1.IsServer)
                {
                    BRGame.ServerStartGame();
                }
            });

            Events.Input.ButtonPressed += (o, e) =>
            {
                if (Game1.IsServer && e.Button.TryGetKeyboard(out Keys key) && key == Keys.RightControl)
                {
                    BRGame.ServerStartGame();
                }

                if (e.Button.TryGetKeyboard(out Keys key2) && key2 == Keys.RightAlt)
                {
                    var loc = Game1.player.currentLocation;
                    int x   = Game1.player.getTileX();
                    int y   = Game1.player.getTileY();


                    Monitor.Log($"tile location={loc.Name}, pos=({x},{y})", LogLevel.Info);

                    Monitor.Log($"my id : {Game1.player.UniqueMultiplayerID}", LogLevel.Info);

                    Monitor.Log($"precise position = {Game1.player.Position}", LogLevel.Info);

                    /*Game1.player.addItemToInventory(new StardewValley.Tools.Slingshot());
                     * Game1.player.addItemToInventory(new StardewValley.Tools.Slingshot(33));
                     *
                     * var xd = new int[] { 388, 390, 378, 380, 384, 382, 386, 441 };
                     * foreach(int asdf in xd)
                     * {
                     *      Game1.player.addItemToInventory(new StardewValley.Object(asdf, 100));
                     * }*/
                }
            };

            Events.GameLoop.UpdateTicked += (o, e) => BRGame?.Update(Game1.currentGameTime);
            Events.GameLoop.UpdateTicked += (o, e) => HitShaker.Update(Game1.currentGameTime);
            Events.GameLoop.UpdateTicked += (o, e) => SpectatorMode.Update();

            //https://github.com/funny-snek/Always-On-Server-for-Multiplayer/blob/master/Always%20On%20Server/ModEntry.cs
            string currentSavedInviteCode = "";

            Events.GameLoop.UpdateTicked += (o, e) =>
            {
                if (e.IsMultipleOf(60 * 5) && Game1.server != null && Game1.options.enableServer == true && !string.Equals(currentSavedInviteCode, Game1.server.getInviteCode()))
                {
                    currentSavedInviteCode = Game1.server.getInviteCode();

                    try
                    {
                        //helper.DirectoryPath
                        StreamWriter sw = new StreamWriter("InviteCode.txt");                        //Should be in the same folder as StardewModdingAPI.exe
                        sw.WriteLine(currentSavedInviteCode);
                        sw.Close();
                    }
                    catch (Exception b)
                    {
                        Console.WriteLine("Exception writing InviteCode: " + b.Message);
                    }
                }
            };

            Events.Player.Warped += (o, e) =>
            {
                if (e.NewLocation != null && (e.NewLocation is StardewValley.Locations.Woods || e.NewLocation.Name == "BugLand"))
                {
                    e.NewLocation.characters.Clear();
                }
            };

            Events.Display.RenderingHud += (o, e) => {
                if (!SpectatorMode.InSpectatorMode)
                {
                    Storm.Draw(Game1.spriteBatch);
                }
            };


            Events.Display.Rendered += (o, e) =>
            {
                if (SpectatorMode.InSpectatorMode)                //Spectator mode can only see the storm when it is drawn above everything
                {
                    Storm.Draw(Game1.spriteBatch);

                    if (Game1.activeClickableMenu == null)
                    {
                        string message = "Spectating";
                        SpriteText.drawStringWithScrollBackground(Game1.spriteBatch, message, Game1.viewport.Width / 2 - SpriteText.getWidthOfString(message) / 2, 16, "", 1f, -1);
                    }
                }
            };

            helper.ConsoleCommands.Add("br_kick", "Kick a player. Usage: br_kick <player ID>", (a, b) =>
            {
                if (!Game1.IsServer)
                {
                    Monitor.Log("Need to be the server host", LogLevel.Info);
                }
                else if (b.Length != 1)
                {
                    Monitor.Log("Need 1 argument", LogLevel.Info);
                }
                else if (!long.TryParse(b[0], out long x))
                {
                    Monitor.Log("Not a valid number", LogLevel.Info);
                }
                else
                {
                    try
                    {
                        var f = Game1.getOnlineFarmers().First(p => p != Game1.player && p.UniqueMultiplayerID == x);
                        NetworkUtility.KickPlayer(f, "You have been kicked by the host.");
                    }
                    catch (Exception)
                    {
                        Monitor.Log($"Could not find player with id {x}", LogLevel.Info);
                    }
                }
            });

            helper.ConsoleCommands.Add("br_setNumberOfPlayerSlots", "Sets the number of player slots. Usage: br_setNumberOfPlayerSlots <number of slots>", (a, b) =>
            {
                if (!Game1.IsServer)
                {
                    Monitor.Log("Need to be the server host", LogLevel.Info);
                }
                else if (b.Length != 1)
                {
                    Monitor.Log("Need 1 argument", LogLevel.Info);
                }
                else if (!int.TryParse(b[0], out int n))
                {
                    Monitor.Log("Not a valid number", LogLevel.Info);
                }
                else
                {
                    n = Math.Abs(n);
                    var emptyCabins = Game1.getFarm().buildings.Where(z => z.daysOfConstructionLeft.Value <= 0 && z.indoors.Value is Cabin).ToArray();

                    if (n > emptyCabins.Length)
                    {
                        for (int i = 0; i < n - emptyCabins.Length; i++)
                        {
                            var blueprint = new BluePrint("Log Cabin");
                            var building  = new Building(blueprint, new Vector2(-10000, 0));
                            Game1.getFarm().buildings.Add(building);

                            try
                            {
                                foreach (var warp in building.indoors.Value.warps)
                                {
                                    //warp.TargetName = "Forest";
                                    Helper.Reflection.GetField <NetString>(warp, "targetName", true).SetValue(new NetString("Forest"));
                                    warp.TargetX = 100;
                                    warp.TargetY = 20;
                                }
                            }
                            catch (Exception) { }
                        }

                        Monitor.Log($"Added {n - emptyCabins.Length} player slots", LogLevel.Info);
                    }
                    else if (n < emptyCabins.Length)
                    {
                        for (int i = 0; i < emptyCabins.Length - n; i++)
                        {
                            Game1.getFarm().buildings.Remove(emptyCabins[i]);
                        }

                        Monitor.Log($"Removed {emptyCabins.Length - n} player slots", LogLevel.Info);
                    }
                    else
                    {
                        Monitor.Log($"There are already {n} player slots", LogLevel.Info);
                    }
                }
            });
        }
        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);
            }
        }