From 91b8bf44acca96ee9c4b33e8c0b9f104156efe1c Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Tue, 8 May 2018 20:40:54 +1000 Subject: [PATCH] More work on games rewrite --- GUI/PropertyWindow/PropertyWindow.Games.cs | 16 +- GUI/Settings/LavaMapProperties.cs | 132 ++-- .../Blocks/Behaviour/WalkthroughBehaviour.cs | 2 +- MCGalaxy/Blocks/Physics/LiquidPhysics.cs | 4 +- .../Blocks/Physics/SimpleLiquidPhysics.cs | 4 +- MCGalaxy/Commands/Command.Helpers.cs | 2 +- MCGalaxy/Commands/Fun/CTF/CmdCtf.cs | 6 +- MCGalaxy/Commands/Fun/CmdLavaSurvival.cs | 166 ++-- MCGalaxy/Commands/Fun/CmdMissile.cs | 5 +- .../Fun/ZombieSurvival/CmdZombieGame.cs | 16 +- .../Commands/World/CmdOverseer.SubCommands.cs | 7 +- MCGalaxy/CorePlugin/ChatHandler.cs | 2 +- MCGalaxy/Drawing/DrawOps/DrawOpPerformer.cs | 2 +- MCGalaxy/Drawing/DrawOps/TriangleDrawOp.cs | 2 +- MCGalaxy/Entity/Entities.cs | 1 - MCGalaxy/Events/IPluginEvent.cs | 9 +- MCGalaxy/Events/ServerEvents.cs | 39 + .../CTF/{CtfPlugin.cs => CtfGame.Plugin.cs} | 105 +-- MCGalaxy/Games/CTF/CtfGame.Round.cs | 152 ++++ MCGalaxy/Games/CTF/CtfGame.cs | 250 ++----- MCGalaxy/Games/CTF/CtfTeam.cs | 57 -- ...tdownPlugin.cs => CountdownGame.Plugin.cs} | 39 +- MCGalaxy/Games/Countdown/CountdownGame.cs | 60 +- MCGalaxy/Games/GameProps.cs | 3 - MCGalaxy/Games/IGame.cs | 26 +- .../{LavaSurvival.Settings.cs => LSConfig.cs} | 60 +- MCGalaxy/Games/LavaSurvival/LSGame.Plugin.cs | 60 ++ .../{LavaSurvival.cs => LSGame.Round.cs} | 707 +++++++----------- MCGalaxy/Games/LavaSurvival/LSGame.cs | 165 ++++ .../Games/LavaSurvival/LavaSurvival.Game.cs | 56 -- MCGalaxy/Games/LevelPicker.cs | 57 +- MCGalaxy/Games/ZombieSurvival/HUD.cs | 17 +- MCGalaxy/Games/ZombieSurvival/LevelPicker.cs | 61 -- MCGalaxy/Games/ZombieSurvival/Rewards.cs | 122 --- MCGalaxy/Games/ZombieSurvival/ZSConfig.cs | 2 - .../{ZSPlugin.cs => ZSGame.Plugin.cs} | 72 +- .../{ZombieGame.Core.cs => ZSGame.Round.cs} | 255 +++++-- .../{ZombieGame.cs => ZSGame.cs} | 257 ++++--- .../Games/ZombieSurvival/ZombieGame.Game.cs | 148 ---- MCGalaxy/Levels/Level.cs | 13 +- MCGalaxy/MCGalaxy_.csproj | 23 +- MCGalaxy/Network/Heartbeat/ClassiCube.cs | 3 +- MCGalaxy/Player/Player.Fields.cs | 2 +- MCGalaxy/Player/Player.Handlers.cs | 35 +- MCGalaxy/Player/Player.Login.cs | 1 - MCGalaxy/Player/Player.cs | 2 +- MCGalaxy/Player/PlayerPhysics.cs | 5 +- MCGalaxy/Server/Server.Fields.cs | 4 +- MCGalaxy/Server/Server.cs | 2 +- MCGalaxy/util/Math/Vectors.cs | 14 +- 50 files changed, 1547 insertions(+), 1703 deletions(-) create mode 100644 MCGalaxy/Events/ServerEvents.cs rename MCGalaxy/Games/CTF/{CtfPlugin.cs => CtfGame.Plugin.cs} (58%) create mode 100644 MCGalaxy/Games/CTF/CtfGame.Round.cs delete mode 100644 MCGalaxy/Games/CTF/CtfTeam.cs rename MCGalaxy/Games/Countdown/{CountdownPlugin.cs => CountdownGame.Plugin.cs} (63%) rename MCGalaxy/Games/LavaSurvival/{LavaSurvival.Settings.cs => LSConfig.cs} (78%) create mode 100644 MCGalaxy/Games/LavaSurvival/LSGame.Plugin.cs rename MCGalaxy/Games/LavaSurvival/{LavaSurvival.cs => LSGame.Round.cs} (53%) create mode 100644 MCGalaxy/Games/LavaSurvival/LSGame.cs delete mode 100644 MCGalaxy/Games/LavaSurvival/LavaSurvival.Game.cs delete mode 100644 MCGalaxy/Games/ZombieSurvival/LevelPicker.cs delete mode 100644 MCGalaxy/Games/ZombieSurvival/Rewards.cs rename MCGalaxy/Games/ZombieSurvival/{ZSPlugin.cs => ZSGame.Plugin.cs} (78%) rename MCGalaxy/Games/ZombieSurvival/{ZombieGame.Core.cs => ZSGame.Round.cs} (54%) rename MCGalaxy/Games/ZombieSurvival/{ZombieGame.cs => ZSGame.cs} (65%) delete mode 100644 MCGalaxy/Games/ZombieSurvival/ZombieGame.Game.cs diff --git a/GUI/PropertyWindow/PropertyWindow.Games.cs b/GUI/PropertyWindow/PropertyWindow.Games.cs index 7ecc6c3cd..dbfe2841f 100644 --- a/GUI/PropertyWindow/PropertyWindow.Games.cs +++ b/GUI/PropertyWindow/PropertyWindow.Games.cs @@ -35,8 +35,8 @@ namespace MCGalaxy.Gui { void UpdateLavaControls() { try { - ls_btnStartGame.Enabled = !Server.lava.active; - ls_btnStopGame.Enabled = Server.lava.active; + ls_btnStartGame.Enabled = !Server.lava.running; + ls_btnStopGame.Enabled = Server.lava.running; ls_btnEndRound.Enabled = Server.lava.roundActive; lsBtnEndVote.Enabled = Server.lava.voteActive; } @@ -44,12 +44,12 @@ namespace MCGalaxy.Gui { } void lsBtnStartGame_Click(object sender, EventArgs e) { - if (!Server.lava.active) Server.lava.Start(); + if (!Server.lava.running) Server.lava.Start(); UpdateLavaControls(); } void lsBtnStopGame_Click(object sender, EventArgs e) { - if (Server.lava.active) Server.lava.Stop(); + if (Server.lava.running) Server.lava.Stop(); UpdateLavaControls(); } @@ -109,9 +109,9 @@ namespace MCGalaxy.Gui { Server.lava.AddMap(name); - LavaSurvival.MapSettings settings = Server.lava.LoadMapSettings(level.name); - settings.blockFlood = new Vec3U16((ushort)(level.Width / 2), (ushort)(level.Height - 1), (ushort)(level.Length / 2)); - settings.blockLayer = new Vec3U16(0, (ushort)(level.Height / 2), 0); + LSGame.MapSettings settings = Server.lava.LoadMapSettings(level.name); + settings.FloodPos = new Vec3U16((ushort)(level.Width / 2), (ushort)(level.Height - 1), (ushort)(level.Length / 2)); + settings.LayerPos = new Vec3U16(0, (ushort)(level.Height / 2), 0); ushort x = (ushort)(level.Width / 2), y = (ushort)(level.Height / 2), z = (ushort)(level.Length / 2); settings.safeZone = new Vec3U16[] { new Vec3U16((ushort)(x - 3), y, (ushort)(z - 3)), new Vec3U16((ushort)(x + 3), (ushort)(y + 4), (ushort)(z + 3)) }; Server.lava.SaveMapSettings(settings); @@ -167,7 +167,7 @@ namespace MCGalaxy.Gui { ls_grpMapSettings.Text = "Map settings (" + name + ")"; try { - LavaSurvival.MapSettings m = Server.lava.LoadMapSettings(name); + LSGame.MapSettings m = Server.lava.LoadMapSettings(name); pg_lavaMap.SelectedObject = new LavaMapProperties(m); } catch (Exception ex) { Logger.LogError(ex); diff --git a/GUI/Settings/LavaMapProperties.cs b/GUI/Settings/LavaMapProperties.cs index decf07313..500fcaa40 100644 --- a/GUI/Settings/LavaMapProperties.cs +++ b/GUI/Settings/LavaMapProperties.cs @@ -1,66 +1,66 @@ -/* - Copyright 2015 MCGalaxy - - Dual-licensed under the Educational Community License, Version 2.0 and - the GNU General Public License, Version 3 (the "Licenses"); you may - not use this file except in compliance with the Licenses. You may - obtain a copy of the Licenses at - - http://www.opensource.org/licenses/ecl2.php - http://www.gnu.org/licenses/gpl-3.0.html - - Unless required by applicable law or agreed to in writing, - software distributed under the Licenses are distributed on an "AS IS" - BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - or implied. See the Licenses for the specific language governing - permissions and limitations under the Licenses. - */ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using MCGalaxy.Games; - -namespace MCGalaxy.Gui { - public sealed class LavaMapProperties { - internal readonly LavaSurvival.MapSettings m; - - public LavaMapProperties(LavaSurvival.MapSettings m) { - this.m = m; - } - - [DisplayName("Fast lava chance")] - public byte FastLava { get { return m.fast; } set { m.fast = Clamp(value); } } - - [DisplayName("Killer liquids chance")] - public byte Killer { get { return m.killer; } set { m.killer = Clamp(value); } } - - [DisplayName("Destroy blocks chance")] - public byte Destroy { get { return m.destroy; } set { m.destroy = Clamp(value); } } - - [DisplayName("Water flood chance")] - public byte Water { get { return m.water; } set { m.water = Clamp(value); } } - - [DisplayName("Layer flood chance")] - public byte Layer { get { return m.layer; } set { m.layer = Clamp(value); } } - - - [DisplayName("Layer height")] - public int LayerHeight { get { return m.layerHeight; } set { m.layerHeight = ClampI(value); } } - - [DisplayName("Layer count")] - public int LayerCount { get { return m.layerCount; } set { m.layerCount = ClampI(value); } } - - [DisplayName("Layer time (mins)")] - public double LayerTime { get { return m.layerInterval; } set { m.layerInterval = ClampD(value); } } - - [DisplayName("Round time (mins)")] - public double RoundTime { get { return m.roundTime; } set { m.roundTime = ClampD(value); } } - - [DisplayName("Flood time (mins)")] - public double FloodTime { get { return m.floodTime; } set { m.floodTime = ClampD(value); } } - - static byte Clamp(byte value) { return Math.Min(value, (byte)100); } - static int ClampI(int value) { return Math.Max(0, Math.Min(value, 1000)); } - static double ClampD(double value) { return Math.Max(0, Math.Min(value, 10)); } - } -} +/* + Copyright 2015 MCGalaxy + + Dual-licensed under the Educational Community License, Version 2.0 and + the GNU General Public License, Version 3 (the "Licenses"); you may + not use this file except in compliance with the Licenses. You may + obtain a copy of the Licenses at + + http://www.opensource.org/licenses/ecl2.php + http://www.gnu.org/licenses/gpl-3.0.html + + Unless required by applicable law or agreed to in writing, + software distributed under the Licenses are distributed on an "AS IS" + BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + or implied. See the Licenses for the specific language governing + permissions and limitations under the Licenses. + */ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using MCGalaxy.Games; + +namespace MCGalaxy.Gui { + public sealed class LavaMapProperties { + internal readonly LSGame.MapSettings m; + + public LavaMapProperties(LSGame.MapSettings m) { + this.m = m; + } + + [DisplayName("Fast lava chance")] + public byte FastLava { get { return m.fast; } set { m.fast = Clamp(value); } } + + [DisplayName("Killer liquids chance")] + public byte Killer { get { return m.killer; } set { m.killer = Clamp(value); } } + + [DisplayName("Destroy blocks chance")] + public byte Destroy { get { return m.destroy; } set { m.destroy = Clamp(value); } } + + [DisplayName("Water flood chance")] + public byte Water { get { return m.water; } set { m.water = Clamp(value); } } + + [DisplayName("Layer flood chance")] + public byte Layer { get { return m.layer; } set { m.layer = Clamp(value); } } + + + [DisplayName("Layer height")] + public int LayerHeight { get { return m.LayerHeight; } set { m.LayerHeight = ClampI(value); } } + + [DisplayName("Layer count")] + public int LayerCount { get { return m.LayerCount; } set { m.LayerCount = ClampI(value); } } + + [DisplayName("Layer time (mins)")] + public double LayerTime { get { return m.layerInterval; } set { m.layerInterval = ClampD(value); } } + + [DisplayName("Round time (mins)")] + public double RoundTime { get { return m.roundTime; } set { m.roundTime = ClampD(value); } } + + [DisplayName("Flood time (mins)")] + public double FloodTime { get { return m.floodTime; } set { m.floodTime = ClampD(value); } } + + static byte Clamp(byte value) { return Math.Min(value, (byte)100); } + static int ClampI(int value) { return Math.Max(0, Math.Min(value, 1000)); } + static double ClampD(double value) { return Math.Max(0, Math.Min(value, 10)); } + } +} diff --git a/MCGalaxy/Blocks/Behaviour/WalkthroughBehaviour.cs b/MCGalaxy/Blocks/Behaviour/WalkthroughBehaviour.cs index 059617fb1..0e4e79cb7 100644 --- a/MCGalaxy/Blocks/Behaviour/WalkthroughBehaviour.cs +++ b/MCGalaxy/Blocks/Behaviour/WalkthroughBehaviour.cs @@ -36,7 +36,7 @@ namespace MCGalaxy.Blocks { } internal static bool Train(Player p, BlockID block, ushort x, ushort y, ushort z) { - if (!p.trainInvincible) p.HandleDeath(Block.Train); + if (!p.trainInvincible && p.level.Config.KillerBlocks) p.HandleDeath(Block.Train); return true; } diff --git a/MCGalaxy/Blocks/Physics/LiquidPhysics.cs b/MCGalaxy/Blocks/Physics/LiquidPhysics.cs index 30e2501b6..0d7aed040 100644 --- a/MCGalaxy/Blocks/Physics/LiquidPhysics.cs +++ b/MCGalaxy/Blocks/Physics/LiquidPhysics.cs @@ -25,7 +25,7 @@ namespace MCGalaxy.Blocks.Physics { public static void PhysWater(Level lvl, ushort x, ushort y, ushort z, BlockID type) { int index; BlockID block = lvl.GetBlock(x, y, z, out index); - if (Server.lava.active && Server.lava.map == lvl && Server.lava.InSafeZone(x, y, z)) + if (Server.lava.running && Server.lava.Map == lvl && Server.lava.InSafeZone(x, y, z)) return; switch (block) { @@ -62,7 +62,7 @@ namespace MCGalaxy.Blocks.Physics { public static void PhysLava(Level lvl, ushort x, ushort y, ushort z, BlockID type) { int index; BlockID block = lvl.GetBlock(x, y, z, out index); - if (Server.lava.active && Server.lava.map == lvl && Server.lava.InSafeZone(x, y, z)) + if (Server.lava.running && Server.lava.Map == lvl && Server.lava.InSafeZone(x, y, z)) return; switch (block) { diff --git a/MCGalaxy/Blocks/Physics/SimpleLiquidPhysics.cs b/MCGalaxy/Blocks/Physics/SimpleLiquidPhysics.cs index c8b879b17..83177b606 100644 --- a/MCGalaxy/Blocks/Physics/SimpleLiquidPhysics.cs +++ b/MCGalaxy/Blocks/Physics/SimpleLiquidPhysics.cs @@ -149,7 +149,7 @@ namespace MCGalaxy.Blocks.Physics { static bool WaterBlocked(Level lvl, ushort x, ushort y, ushort z) { BlockID block = lvl.GetBlock(x, y, z); - if (Server.lava.active && Server.lava.map == lvl && Server.lava.InSafeZone(x, y, z)) + if (Server.lava.running && Server.lava.Map == lvl && Server.lava.InSafeZone(x, y, z)) return true; switch (block) { @@ -261,7 +261,7 @@ namespace MCGalaxy.Blocks.Physics { static bool LavaBlocked(Level lvl, ushort x, ushort y, ushort z) { BlockID block = lvl.GetBlock(x, y, z); - if (Server.lava.active && Server.lava.map == lvl && Server.lava.InSafeZone(x, y, z)) + if (Server.lava.running && Server.lava.Map == lvl && Server.lava.InSafeZone(x, y, z)) return true; switch (block) { diff --git a/MCGalaxy/Commands/Command.Helpers.cs b/MCGalaxy/Commands/Command.Helpers.cs index 6ff5dbee1..a28185721 100644 --- a/MCGalaxy/Commands/Command.Helpers.cs +++ b/MCGalaxy/Commands/Command.Helpers.cs @@ -30,7 +30,7 @@ namespace MCGalaxy { if (enable == CommandEnable.Economy && !Economy.Enabled) return "economy is disabled."; - if (enable == bothFlags && !(Server.zombie.Running || Server.lava.active)) + if (enable == bothFlags && !(Server.zombie.Running || Server.lava.running)) return "neither zombie nor lava survival is running."; if (enable == CommandEnable.Zombie && !Server.zombie.Running) return "zombie survival is not running."; diff --git a/MCGalaxy/Commands/Fun/CTF/CmdCtf.cs b/MCGalaxy/Commands/Fun/CTF/CmdCtf.cs index e769c67b9..686538ada 100644 --- a/MCGalaxy/Commands/Fun/CTF/CmdCtf.cs +++ b/MCGalaxy/Commands/Fun/CTF/CmdCtf.cs @@ -72,10 +72,10 @@ namespace MCGalaxy.Commands.Fun { void HandleStop(Player p) { if (!CheckExtraPerm(p, 1)) return; - if (Server.ctf == null || !Server.ctf.started) { - Player.Message(p, "No CTF game is active."); return; + if (Server.ctf == null || !Server.ctf.Running) { + Player.Message(p, "CTF is not running"); return; } - Server.ctf.Stop(); + Server.ctf.End(); } diff --git a/MCGalaxy/Commands/Fun/CmdLavaSurvival.cs b/MCGalaxy/Commands/Fun/CmdLavaSurvival.cs index f4aa25d48..db51bd9f2 100644 --- a/MCGalaxy/Commands/Fun/CmdLavaSurvival.cs +++ b/MCGalaxy/Commands/Fun/CmdLavaSurvival.cs @@ -34,36 +34,36 @@ namespace MCGalaxy.Commands.Fun { public override void Use(Player p, string message) { if (message.Length == 0) { Help(p); return; } string[] args = message.ToLower().SplitSpaces(); - + LSGame game = Server.lava; + switch (args[0]) { - case "go": HandleGo(p, args); return; - case "info": HandleInfo(p, args); return; - case "start": HandleStart(p, args); return; - case "stop": HandleStop(p, args); return; - case "end": HandleEnd(p, args); return; - case "setup": HandleSetup(p, args); return; + case "go": HandleGo(p, game); return; + case "info": HandleInfo(p, game); return; + case "start": HandleStart(p, args, game); return; + case "stop": HandleStop(p, game); return; + case "end": HandleEnd(p, game); return; + case "setup": HandleSetup(p, args, game); return; } Help(p); } - void HandleGo(Player p, string[] args) { - if (p == null) { Player.Message(p, "/{0} go can only be used in-game.", name); return; } - if (!Server.lava.active) { Player.Message(p, "There is no Lava Survival game right now."); return; } - PlayerActions.ChangeMap(p, Server.lava.map.name); + void HandleGo(Player p, LSGame game) { + if (!game.Running) { Player.Message(p, "Lava survival is not running"); return; } + PlayerActions.ChangeMap(p, game.Map); } - void HandleInfo(Player p, string[] args) { - if (!Server.lava.active) { Player.Message(p, "There is no Lava Survival game right now."); return; } - if (!Server.lava.roundActive) { Player.Message(p, "The round of Lava Survival hasn't started yet."); return; } - Server.lava.AnnounceRoundInfo(p, p == null); - Server.lava.AnnounceTimeLeft(!Server.lava.flooded, true, p, p == null); + void HandleInfo(Player p, LSGame game) { + if (!game.Running) { Player.Message(p, "Lava survival is not running"); return; } + if (!game.roundActive) { Player.Message(p, "The round of Lava Survival hasn't started yet."); return; } + game.AnnounceRoundInfo(p, p == null); + game.AnnounceTimeLeft(!game.flooded, true, p, p == null); } - void HandleStart(Player p, string[] args) { + void HandleStart(Player p, string[] args, LSGame game) { if (!CheckExtraPerm(p, 1)) return; string map = args.Length > 1 ? args[1] : ""; - switch (Server.lava.Start(map)) { + switch (game.Start(map)) { case 0: Chat.MessageGlobal("Lava Survival has started! Join the fun with /ls go"); return; case 1: Player.Message(p, "There is already an active Lava Survival game."); return; case 2: Player.Message(p, "You must have at least 3 configured maps to play Lava Survival."); return; @@ -72,142 +72,141 @@ namespace MCGalaxy.Commands.Fun { } } - void HandleStop(Player p, string[] args) { + void HandleStop(Player p, LSGame game) { if (!CheckExtraPerm(p, 1)) return; - - switch (Server.lava.Stop()) { - case 0: Chat.MessageGlobal("Lava Survival has ended! We hope you had fun!"); return; - case 1: Player.Message(p, "There isn't an active Lava Survival game."); return; - default: Player.Message(p, "An unknown error occurred."); return; + if (!game.Running) { + Player.Message(p, "Lava survival is not running"); + } else { + game.End(); + Chat.MessageGlobal("Lava Survival has ended! We hope you had fun!"); } } - void HandleEnd(Player p, string[] args) { + void HandleEnd(Player p, LSGame game) { if (!CheckExtraPerm(p, 1)) return; - if (!Server.lava.active) { Player.Message(p, "There isn't an active Lava Survival game."); return; } - if (Server.lava.roundActive) Server.lava.EndRound(); - else if (Server.lava.voteActive) Server.lava.EndVote(); + if (!game.Running) { Player.Message(p, "Lava survival is not running"); return; } + if (game.roundActive) game.EndRound(); + else if (game.voteActive) game.EndVote(); else Player.Message(p, "There isn't an active round or vote to end."); } - void HandleSetup(Player p, string[] args) { + void HandleSetup(Player p, string[] args, LSGame game) { if (!CheckExtraPerm(p, 1)) return; if (p == null) { Player.Message(p, "/{0} setup can only be used in-game.", name); return; } if (args.Length < 2) { SetupHelp(p); return; } - if (Server.lava.active) { Player.Message(p, "You cannot configure Lava Survival while a game is active."); return; } + if (game.Running) { Player.Message(p, "You cannot configure Lava Survival while a game is active."); return; } string group = args[1]; if (group.CaselessEq("map")) { - HandleSetupMap(p, args); + HandleSetupMap(p, args, game); } else if (group.CaselessEq("block")) { - HandleSetupBlock(p, args); + HandleSetupBlock(p, args, game); } else if (group.CaselessEq("safe") || group.CaselessEq("safezone")) { - HandleSetupSafeZone(p, args); + HandleSetupSafeZone(p, args, game); } else if (group.CaselessEq("settings")) { - HandleSetupSettings(p, args); + HandleSetupSettings(p, args, game); } else if (group.CaselessEq("mapsettings")) { - HandleSetupMapSettings(p, args); + HandleSetupMapSettings(p, args, game); } else { SetupHelp(p); } } - void HandleSetupMap(Player p, string[] args) { + void HandleSetupMap(Player p, string[] args, LSGame game) { if (args.Length < 3) { SetupHelp(p, "map"); return; } Level lvl = Matcher.FindLevels(p, args[2]); if (lvl == null) return; if (lvl == Server.mainLevel) { Player.Message(p, "You cannot use the main map for Lava Survival."); return; } - if (Server.lava.HasMap(lvl.name)) { - Server.lava.RemoveMap(lvl.name); + if (game.HasMap(lvl.name)) { + game.RemoveMap(lvl.name); lvl.Config.PhysicsOverload = 1500; lvl.Config.AutoUnload = true; lvl.Config.LoadOnGoto = true; Player.Message(p, "Map {0} %Shas been removed.", lvl.ColoredName); } else { - Server.lava.AddMap(lvl.name); + game.AddMap(lvl.name); - LavaSurvival.MapSettings settings = Server.lava.LoadMapSettings(lvl.name); - settings.blockFlood = new Vec3U16((ushort)(lvl.Width / 2), (ushort)(lvl.Height - 1), (ushort)(lvl.Length / 2)); - settings.blockLayer = new Vec3U16(0, (ushort)(lvl.Height / 2), 0); + LSGame.MapSettings settings = game.LoadMapSettings(lvl.name); + settings.FloodPos = new Vec3U16((ushort)(lvl.Width / 2), (ushort)(lvl.Height - 1), (ushort)(lvl.Length / 2)); + settings.LayerPos = new Vec3U16(0, (ushort)(lvl.Height / 2), 0); ushort x = (ushort)(lvl.Width / 2), y = (ushort)(lvl.Height / 2), z = (ushort)(lvl.Length / 2); settings.safeZone = new Vec3U16[] { new Vec3U16((ushort)(x - 3), y, (ushort)(z - 3)), new Vec3U16((ushort)(x + 3), (ushort)(y + 4), (ushort)(z + 3)) }; - Server.lava.SaveMapSettings(settings); + game.SaveMapSettings(settings); lvl.Config.PhysicsOverload = 1000000; - lvl.Config.AutoUnload = false; lvl.Config.LoadOnGoto = false; Player.Message(p, "Map {0} %Shas been added.", lvl.ColoredName); } Level.SaveSettings(lvl); } - void HandleSetupBlock(Player p, string[] args) { - if (!Server.lava.HasMap(p.level.name)) { Player.Message(p, "Add the map before configuring it."); return; } + void HandleSetupBlock(Player p, string[] args, LSGame game) { + if (!game.HasMap(p.level.name)) { Player.Message(p, "Add the map before configuring it."); return; } if (args.Length < 3) { SetupHelp(p, "block"); return; } if (args[2] == "flood") { Player.Message(p, "Place or destroy the block you want to be the total flood block spawn point."); - p.MakeSelection(1, null, SetFloodPos); + p.MakeSelection(1, game, SetFloodPos); } else if (args[2] == "layer") { Player.Message(p, "Place or destroy the block you want to be the layer flood base spawn point."); - p.MakeSelection(1, null, SetFloodLayerPos); + p.MakeSelection(1, game, SetFloodLayerPos); } else { SetupHelp(p, "block"); } } - void HandleSetupSafeZone(Player p, string[] args) { + void HandleSetupSafeZone(Player p, string[] args, LSGame game) { Player.Message(p, "Place or break two blocks to determine the edges."); - p.MakeSelection(2, null, SetSafeZone); + p.MakeSelection(2, game, SetSafeZone); } - void HandleSetupSettings(Player p, string[] args) { + void HandleSetupSettings(Player p, string[] args, LSGame game) { if (args.Length < 3) { - Player.Message(p, "Maps: &b" + Server.lava.Maps.Join(", ")); - Player.Message(p, "Start on server startup: " + (Server.lava.startOnStartup ? "&aON" : "&cOFF")); - Player.Message(p, "Send AFK to main: " + (Server.lava.sendAfkMain ? "&aON" : "&cOFF")); - Player.Message(p, "Vote count: &b" + Server.lava.voteCount); - Player.Message(p, "Vote time: &b" + Server.lava.voteTime + " minutes"); + Player.Message(p, "Maps: &b" + game.Maps.Join(", ")); + Player.Message(p, "Start on server startup: " + (game.startOnStartup ? "&aON" : "&cOFF")); + Player.Message(p, "Send AFK to main: " + (game.sendAfkMain ? "&aON" : "&cOFF")); + Player.Message(p, "Vote count: &b" + game.voteCount); + Player.Message(p, "Vote time: &b" + game.voteTime + " minutes"); return; } string opt = args[2], value = args.Length > 3 ? args[3] : ""; TimeSpan span = default(TimeSpan); if (opt.CaselessEq("sendafkmain")) { - Server.lava.sendAfkMain = !Server.lava.sendAfkMain; - Player.Message(p, "Send AFK to main: " + (Server.lava.sendAfkMain ? "&aON" : "&cOFF")); + game.sendAfkMain = !game.sendAfkMain; + Player.Message(p, "Send AFK to main: " + (game.sendAfkMain ? "&aON" : "&cOFF")); } else if (opt.CaselessEq("votecount")) { - if (!CommandParser.GetByte(p, value, "Count", ref Server.lava.voteCount, 2, 10)) return; - Player.Message(p, "Vote count: &b" + Server.lava.voteCount); + if (!CommandParser.GetByte(p, value, "Count", ref game.voteCount, 2, 10)) return; + Player.Message(p, "Vote count: &b" + game.voteCount); } else if (opt.CaselessEq("votetime")) { if (!CommandParser.GetTimespan(p, value, ref span, "set time to", "m")) return; - Server.lava.voteTime = span.TotalMinutes; + game.voteTime = span.TotalMinutes; Player.Message(p, "Vote time: &b" + span.Shorten(true)); } else { SetupHelp(p, "settings"); return; } - Server.lava.SaveSettings(); + game.SaveSettings(); } - void HandleSetupMapSettings(Player p, string[] args) { - if (!Server.lava.HasMap(p.level.name)) { Player.Message(p, "Add the map before configuring it."); return; } - LavaSurvival.MapSettings settings = Server.lava.LoadMapSettings(p.level.name); + void HandleSetupMapSettings(Player p, string[] args, LSGame game) { + if (!game.HasMap(p.level.name)) { Player.Message(p, "Add the map before configuring it."); return; } + LSGame.MapSettings settings = game.LoadMapSettings(p.level.name); if (args.Length < 4) { Player.Message(p, "Fast lava chance: &b" + settings.fast + "%"); Player.Message(p, "Killer lava/water chance: &b" + settings.killer + "%"); Player.Message(p, "Destroy blocks chance: &b" + settings.destroy + "%"); Player.Message(p, "Water flood chance: &b" + settings.water + "%"); Player.Message(p, "Layer flood chance: &b" + settings.layer + "%"); - Player.Message(p, "Layer height: &b" + settings.layerHeight + " blocks"); - Player.Message(p, "Layer count: &b" + settings.layerCount); + Player.Message(p, "Layer height: &b" + settings.LayerHeight + " blocks"); + Player.Message(p, "Layer count: &b" + settings.LayerCount); Player.Message(p, "Layer time: &b" + settings.layerInterval + " minutes"); Player.Message(p, "Round time: &b" + settings.roundTime + " minutes"); Player.Message(p, "Flood time: &b" + settings.floodTime + " minutes"); - Player.Message(p, "Flood position: &b" + settings.blockFlood.ToString(", ")); - Player.Message(p, "Layer position: &b" + settings.blockLayer.ToString(", ")); + Player.Message(p, "Flood position: &b" + settings.FloodPos.ToString(", ")); + Player.Message(p, "Layer position: &b" + settings.LayerPos.ToString(", ")); Player.Message(p, "Safe zone: &b({0}) ({1})", settings.safeZone[0].ToString(", "), settings.safeZone[1].ToString(", ")); return; } @@ -235,12 +234,12 @@ namespace MCGalaxy.Commands.Fun { Player.Message(p, "Layer flood chance: &b" + settings.layer + "%"); break; case "layerheight": - settings.layerHeight = int.Parse(args[3]); - Player.Message(p, "Layer height: &b" + settings.layerHeight + " blocks"); + settings.LayerHeight = int.Parse(args[3]); + Player.Message(p, "Layer height: &b" + settings.LayerHeight + " blocks"); break; case "layercount": - settings.layerCount = int.Parse(args[3]); - Player.Message(p, "Layer count: &b" + settings.layerCount); + settings.LayerCount = int.Parse(args[3]); + Player.Message(p, "Layer count: &b" + settings.LayerCount); break; case "layertime": settings.layerInterval = double.Parse(args[3]); @@ -258,7 +257,7 @@ namespace MCGalaxy.Commands.Fun { SetupHelp(p, "mapsettings"); return; } } catch { Player.Message(p, "INVALID INPUT"); return; } - Server.lava.SaveMapSettings(settings); + game.SaveMapSettings(settings); } public override void Help(Player p) { @@ -313,18 +312,20 @@ namespace MCGalaxy.Commands.Fun { bool SetFloodPos(Player p, Vec3S32[] m, object state, BlockID block) { - LavaSurvival.MapSettings settings = Server.lava.LoadMapSettings(p.level.name); - settings.blockFlood = (Vec3U16)m[0]; - Server.lava.SaveMapSettings(settings); + LSGame game = (LSGame)state; + LSGame.MapSettings settings = game.LoadMapSettings(p.level.name); + settings.FloodPos = (Vec3U16)m[0]; + game.SaveMapSettings(settings); Player.Message(p, "Position set! &b({0}, {1}, {2})", m[0].X, m[0].Y, m[0].Z); return false; } bool SetFloodLayerPos(Player p, Vec3S32[] m, object state, BlockID block) { - LavaSurvival.MapSettings settings = Server.lava.LoadMapSettings(p.level.name); - settings.blockLayer = (Vec3U16)m[0]; - Server.lava.SaveMapSettings(settings); + LSGame game = (LSGame)state; + LSGame.MapSettings settings = game.LoadMapSettings(p.level.name); + settings.LayerPos = (Vec3U16)m[0]; + game.SaveMapSettings(settings); Player.Message(p, "Position set! &b({0}, {1}, {2})", m[0].X, m[0].Y, m[0].Z); return false; @@ -333,10 +334,11 @@ namespace MCGalaxy.Commands.Fun { bool SetSafeZone(Player p, Vec3S32[] m, object state, BlockID block) { Vec3S32 min = Vec3S32.Min(m[0], m[1]); Vec3S32 max = Vec3S32.Max(m[0], m[1]); + LSGame game = (LSGame)state; - LavaSurvival.MapSettings settings = Server.lava.LoadMapSettings(p.level.name); + LSGame.MapSettings settings = game.LoadMapSettings(p.level.name); settings.safeZone = new Vec3U16[] { (Vec3U16)min, (Vec3U16)max }; - Server.lava.SaveMapSettings(settings); + game.SaveMapSettings(settings); Player.Message(p, "Safe zone set! &b({0}, {1}, {2}) ({3}, {4}, {5})", min.X, min.Y, min.Z, max.X, max.Y, max.Z); diff --git a/MCGalaxy/Commands/Fun/CmdMissile.cs b/MCGalaxy/Commands/Fun/CmdMissile.cs index 55c3e8236..e1b03a4cc 100644 --- a/MCGalaxy/Commands/Fun/CmdMissile.cs +++ b/MCGalaxy/Commands/Fun/CmdMissile.cs @@ -123,12 +123,11 @@ namespace MCGalaxy.Commands.Fun { Player pl = GetPlayer(args.player, pos, true); if (pl == null) return false; - BlockID stone = Block.Cobblestone; Player p = args.player; if (p.level.physics >= 3 && args.weaponType >= WeaponType.Explode) { - pl.HandleDeath(stone, "@p %Swas blown up by " + p.ColoredName, true); + pl.HandleDeath(Block.Cobblestone, "@p %Swas blown up by " + p.ColoredName, true); } else { - pl.HandleDeath(stone, "@p %Swas hit by a missile from " + p.ColoredName); + pl.HandleDeath(Block.Cobblestone, "@p %Swas hit by a missile from " + p.ColoredName); } return true; } diff --git a/MCGalaxy/Commands/Fun/ZombieSurvival/CmdZombieGame.cs b/MCGalaxy/Commands/Fun/ZombieSurvival/CmdZombieGame.cs index 5a73bf3eb..0487833ad 100644 --- a/MCGalaxy/Commands/Fun/ZombieSurvival/CmdZombieGame.cs +++ b/MCGalaxy/Commands/Fun/ZombieSurvival/CmdZombieGame.cs @@ -69,7 +69,7 @@ namespace MCGalaxy.Commands.Fun { Player.Message(p, "Zombie Survival running, with " + (game.RoundsLeft + 1) + " rounds left"); break; } - Player.Message(p, "Running on map: " + game.MapName); + Player.Message(p, "Running on map: " + game.Map.ColoredName); } void HandleStart(Player p, ZSGame game, string[] args) { @@ -97,18 +97,10 @@ namespace MCGalaxy.Commands.Fun { void HandleStop(Player p, ZSGame game) { if (!CheckExtraPerm(p, 1)) return; if (!game.Running) { - Player.Message(p, "There is no Zombie Survival game currently in progress."); return; + Player.Message(p, "Zombie Survival is not running"); + } else { + game.End(); } - - string src = p == null ? "(console)" : p.ColoredName; - Level lvl = game.Map; - if (lvl != null) { - Chat.MessageLevel(game.Map, "Zombie Survival was stopped by " + src); - } - - src = p == null ? "(console)" : p.name; - Logger.Log(LogType.GameActivity, "Zombie Survival stopped by " + src); - game.End(); } void HandleSet(Player p, ZSGame game, string[] args) { diff --git a/MCGalaxy/Commands/World/CmdOverseer.SubCommands.cs b/MCGalaxy/Commands/World/CmdOverseer.SubCommands.cs index 0c6b0e3cf..9b7d61229 100644 --- a/MCGalaxy/Commands/World/CmdOverseer.SubCommands.cs +++ b/MCGalaxy/Commands/World/CmdOverseer.SubCommands.cs @@ -132,11 +132,8 @@ namespace MCGalaxy.Commands.World { Group grp = Matcher.FindRanks(p, rank); if (grp != null) p.level.BuildAccess.SetMin(null, p.level, grp); } else if (cmd == "TEXTURE" || cmd == "TEXTUREZIP" || cmd == "TEXTUREPACK") { - if (value.Length == 0) { - Command.all.FindByName("Texture").Use(p, "levelzip normal"); - } else { - Command.all.FindByName("Texture").Use(p, "levelzip " + value); - } + if (value.Length == 0) value = "normal"; + Command.all.FindByName("Texture").Use(p, "levelzip " + value); } else { cmd = LevelOptions.Map(cmd.ToLower()); if (cmd == "physicspeed" || cmd == "overload" || cmd == "realmowner") { diff --git a/MCGalaxy/CorePlugin/ChatHandler.cs b/MCGalaxy/CorePlugin/ChatHandler.cs index 1d51f0cca..e952a681e 100644 --- a/MCGalaxy/CorePlugin/ChatHandler.cs +++ b/MCGalaxy/CorePlugin/ChatHandler.cs @@ -30,7 +30,7 @@ namespace MCGalaxy.Core { if (cmd == "pony") { p.cancelcommand = true; if (!MessageCmd.CanSpeak(p, cmd)) return; - int ponycount = p.Extras.GetInt("MCGalaxy_Core_Pony", 0); + int ponycount = p.Extras.GetInt("MCGalaxy_Core_Pony", 0); if (ponycount < 2) { Chat.MessageGlobal("{0} %Sjust so happens to be a proud brony! Everyone give {0} %Sa brohoof!", p.ColoredName); diff --git a/MCGalaxy/Drawing/DrawOps/DrawOpPerformer.cs b/MCGalaxy/Drawing/DrawOps/DrawOpPerformer.cs index a268d15ac..72e7a9420 100644 --- a/MCGalaxy/Drawing/DrawOps/DrawOpPerformer.cs +++ b/MCGalaxy/Drawing/DrawOps/DrawOpPerformer.cs @@ -180,7 +180,7 @@ namespace MCGalaxy.Drawing.Ops { // Check to make sure the block is actually different and that we can change it if (old == b.Block || !lvl.CheckAffectPermissions(p, b.X, b.Y, b.Z, old, b.Block)) return; - // Set the block (inlined) + // Set the block (inlined) lvl.Changed = true; if (b.Block >= Block.Extended) { #if TEN_BIT_BLOCKS diff --git a/MCGalaxy/Drawing/DrawOps/TriangleDrawOp.cs b/MCGalaxy/Drawing/DrawOps/TriangleDrawOp.cs index 5ca5c503c..6df68bf95 100644 --- a/MCGalaxy/Drawing/DrawOps/TriangleDrawOp.cs +++ b/MCGalaxy/Drawing/DrawOps/TriangleDrawOp.cs @@ -71,7 +71,7 @@ namespace MCGalaxy.Drawing.Ops { } } - private bool Axis(Vec3F32 P, Vec3F32 P1, Vec3F32 P2) { + bool Axis(Vec3F32 P, Vec3F32 P1, Vec3F32 P2) { // Point to line segment test float bottom = (P2 - P1).LengthSquared; if (bottom == 0) return (P1 - P).Length <= 0.5f; diff --git a/MCGalaxy/Entity/Entities.cs b/MCGalaxy/Entity/Entities.cs index 84fc44c30..3436d5ccb 100644 --- a/MCGalaxy/Entity/Entities.cs +++ b/MCGalaxy/Entity/Entities.cs @@ -44,7 +44,6 @@ namespace MCGalaxy { /// Spawns this player to all other players that can see the player in the current world. public static void GlobalSpawn(Player p, Position pos, Orientation rot, bool self, string possession = "") { Player[] players = PlayerInfo.Online.Items; - p.Game.lastSpawnColor = p.Game.Infected ? ZSGame.InfectCol : p.color; TabList.Update(p, self); foreach (Player other in players) { diff --git a/MCGalaxy/Events/IPluginEvent.cs b/MCGalaxy/Events/IPluginEvent.cs index 22431273b..821100969 100644 --- a/MCGalaxy/Events/IPluginEvent.cs +++ b/MCGalaxy/Events/IPluginEvent.cs @@ -99,13 +99,10 @@ namespace MCGalaxy.Events { Logger.LogError(ex); } - static string MethodFormat(string format, IMethod handler) { - return String.Format(format, GetFullMethodName(handler), typeof(IMethod).Name); - } - - static string GetFullMethodName(object method) { + static string MethodFormat(string format, IMethod method) { Delegate del = (Delegate)((object)method); - return del.Method.ReflectedType.FullName + "." + del.Method.Name; + string fullName = del.Method.ReflectedType.FullName + "." + del.Method.Name; + return String.Format(format, fullName, typeof(IMethod).Name); } } } diff --git a/MCGalaxy/Events/ServerEvents.cs b/MCGalaxy/Events/ServerEvents.cs new file mode 100644 index 000000000..62d6b94f2 --- /dev/null +++ b/MCGalaxy/Events/ServerEvents.cs @@ -0,0 +1,39 @@ +/* + Copyright 2011 MCForge + + Dual-licensed under the Educational Community License, Version 2.0 and + the GNU General Public License, Version 3 (the "Licenses"); you may + not use this file except in compliance with the Licenses. You may + obtain a copy of the Licenses at + + http://www.opensource.org/licenses/ecl2.php + http://www.gnu.org/licenses/gpl-3.0.html + + Unless required by applicable law or agreed to in writing, + software distributed under the Licenses are distributed on an "AS IS" + BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + or implied. See the Licenses for the specific language governing + permissions and limitations under the Licenses. + */ +using System; +using System.Collections.Generic; +using MCGalaxy.Network; + +namespace MCGalaxy.Events.ServerEvents { + + public delegate void OnSendingHeartbeat(Heartbeat service, ref string name); + public sealed class OnSendingHeartbeatEvent : IEvent { + + public static void Call(Heartbeat service, ref string name) { + IEvent[] items = handlers.Items; + // Can't use CallCommon because we need to pass arguments by ref + for (int i = 0; i < items.Length; i++) { + try { + items[i].method(service, ref name); + } catch (Exception ex) { + LogHandlerException(ex, items[i]); + } + } + } + } +} diff --git a/MCGalaxy/Games/CTF/CtfPlugin.cs b/MCGalaxy/Games/CTF/CtfGame.Plugin.cs similarity index 58% rename from MCGalaxy/Games/CTF/CtfPlugin.cs rename to MCGalaxy/Games/CTF/CtfGame.Plugin.cs index bc2849b45..a8646d0b8 100644 --- a/MCGalaxy/Games/CTF/CtfPlugin.cs +++ b/MCGalaxy/Games/CTF/CtfGame.Plugin.cs @@ -25,13 +25,9 @@ using MCGalaxy.Maths; using BlockID = System.UInt16; namespace MCGalaxy.Games { - public sealed class CtfPlugin : Plugin_Simple { - public override string creator { get { return Server.SoftwareName + " team"; } } - public override string MCGalaxy_Version { get { return Server.VersionString; } } - public override string name { get { return "Core_CTFPlugin"; } } - public CTFGame Game; + public sealed partial class CTFGame : RoundsGame { - public override void Load(bool startup) { + void HookEventHandlers() { OnPlayerDeathEvent.Register(HandlePlayerDeath, Priority.High); OnPlayerChatEvent.Register(HandlePlayerChat, Priority.High); OnPlayerCommandEvent.Register(HandlePlayerCommand, Priority.High); @@ -45,7 +41,7 @@ namespace MCGalaxy.Games { OnJoinedLevelEvent.Register(HandleOnJoinedLevel, Priority.High); } - public override void Unload(bool shutdown) { + void UnhookEventHandlers() { OnPlayerDeathEvent.Unregister(HandlePlayerDeath); OnPlayerChatEvent.Unregister(HandlePlayerChat); OnPlayerCommandEvent.Unregister(HandlePlayerCommand); @@ -61,38 +57,19 @@ namespace MCGalaxy.Games { void HandlePlayerDeath(Player p, BlockID deathblock) { - if (!Game.started || p.level != Game.Map) return; - if (!Game.Get(p).hasflag) return; + if (!running || p.level != Map) return; + if (!Get(p).hasflag) return; - CtfTeam2 team = Game.TeamOf(p); - if (team != null) Game.DropFlag(p, team); + CtfTeam2 team = TeamOf(p); + if (team != null) DropFlag(p, team); } void HandlePlayerChat(Player p, string message) { - if (Game.voting) { - if (message == "1" || message.CaselessEq(Game.map1)) { - Player.Message(p, "Thanks for voting :D"); - Game.vote1++; - p.cancelchat = true; - } else if (message == "2" || message.CaselessEq(Game.map2)) { - Player.Message(p, "Thanks for voting :D"); - Game.vote2++; - p.cancelchat = true; - } else if (message == "3" || message.CaselessEq(Game.map3)) { - Player.Message(p, "Thanks for voting :D"); - Game.vote3++; - p.cancelchat = true; - } else { - Player.Message(p, "%2VOTE:"); - Player.Message(p, "1. " + Game.map1 + " 2. " + Game.map2 + " 3. " + Game.map3); - p.cancelchat = true; - } - } + if (Picker.HandlesMessage(p, message)) { p.cancelchat = true; return; } + if (!running || p.level != Map) return; + if (!Get(p).TeamChatting) return; - if (!Game.started || p.level != Game.Map) return; - if (!Game.Get(p).TeamChatting) return; - - CtfTeam2 team = Game.TeamOf(p); + CtfTeam2 team = TeamOf(p); if (team == null) return; Player[] members = team.Members.Items; @@ -103,8 +80,8 @@ namespace MCGalaxy.Games { } void HandleBlockChange(Player p, ushort x, ushort y, ushort z, BlockID block, bool placing) { - if (!Game.started || p.level != Game.Map) return; - CtfTeam2 team = Game.TeamOf(p); + if (!running || p.level != Map) return; + CtfTeam2 team = TeamOf(p); if (team == null) { p.RevertBlock(x, y, z); Player.Message(p, "You are not on a team!"); @@ -113,43 +90,43 @@ namespace MCGalaxy.Games { } Vec3U16 pos = new Vec3U16(x, y, z); - if (pos == Game.Opposing(team).FlagPos && !Game.Map.IsAirAt(x, y, z)) { - Game.TakeFlag(p, team); + if (pos == Opposing(team).FlagPos && !Map.IsAirAt(x, y, z)) { + TakeFlag(p, team); } - if (pos == team.FlagPos && !Game.Map.IsAirAt(x, y, z)) { - Game.ReturnFlag(p, team); + if (pos == team.FlagPos && !Map.IsAirAt(x, y, z)) { + ReturnFlag(p, team); } } void HandleDisconnect(Player p, string reason) { - if (p.level != Game.Map) return; - CtfTeam2 team = Game.TeamOf(p); + if (p.level != Map) return; + CtfTeam2 team = TeamOf(p); if (team == null) return; - Game.DropFlag(p, team); + DropFlag(p, team); team.Remove(p); - Chat.MessageLevel(Game.Map, team.Color + p.DisplayName + " %Sleft the ctf game"); + Chat.MessageLevel(Map, team.Color + p.DisplayName + " %Sleft the ctf game"); } void HandleLevelUnload(Level lvl) { - if (Game.started && lvl == Game.Map) { + if (running && lvl == Map) { Logger.Log(LogType.GameActivity, "Unload Failed!, A ctf game is currently going on!"); lvl.cancelunload = true; } } void HandlePlayerSpawning(Player p, ref Position pos, ref byte yaw, ref byte pitch, bool respawning) { - if (!Game.started || p.level != Game.Map) return; + if (!running || p.level != Map) return; - CtfTeam2 team = Game.TeamOf(p); + CtfTeam2 team = TeamOf(p); if (team != null) pos = team.SpawnPos; - if (team != null && respawning) Game.DropFlag(p, team); + if (team != null && respawning) DropFlag(p, team); } void HandleTabListEntryAdded(Entity entity, ref string tabName, ref string tabGroup, Player dst) { Player p = entity as Player; - if (p == null || !Game.started || p.level != Game.Map) return; - CtfTeam2 team = Game.TeamOf(p); + if (p == null || !running || p.level != Map) return; + CtfTeam2 team = TeamOf(p); if (p.Game.Referee) { tabGroup = "&2Referees"; @@ -161,31 +138,31 @@ namespace MCGalaxy.Games { } void HandleOnJoinedLevel(Player p, Level prevLevel, Level level) { - if (p == null || !Game.started) return; + if (p == null || !running) return; - if (prevLevel == Game.Map) { - CtfTeam2 team = Game.TeamOf(p); + if (prevLevel == Map) { + CtfTeam2 team = TeamOf(p); if (team == null) return; - Game.DropFlag(p, team); + DropFlag(p, team); team.Remove(p); - Chat.MessageLevel(Game.Map, team.Color + p.DisplayName + " %Sleft the ctf game"); - } else if (level == Game.Map) { - if (Game.Blue.Members.Count > Game.Red.Members.Count) { - Game.JoinTeam(p, Game.Red); - } else if (Game.Red.Members.Count > Game.Blue.Members.Count) { - Game.JoinTeam(p, Game.Blue); + Chat.MessageLevel(Map, team.Color + p.DisplayName + " %Sleft the ctf game"); + } else if (level == Map) { + if (Blue.Members.Count > Red.Members.Count) { + JoinTeam(p, Red); + } else if (Red.Members.Count > Blue.Members.Count) { + JoinTeam(p, Blue); } else if (new Random().Next(2) == 0) { - Game.JoinTeam(p, Game.Red); + JoinTeam(p, Red); } else { - Game.JoinTeam(p, Game.Blue); + JoinTeam(p, Blue); } } } void HandlePlayerCommand(Player p, string cmd, string args) { - if (!Game.started || p.level != Game.Map || cmd != "teamchat") return; - CtfData data = Game.Get(p); + if (!running || p.level != Map || cmd != "teamchat") return; + CtfData data = Get(p); if (data == null) return; if (data.TeamChatting) { diff --git a/MCGalaxy/Games/CTF/CtfGame.Round.cs b/MCGalaxy/Games/CTF/CtfGame.Round.cs new file mode 100644 index 000000000..0f97e9afa --- /dev/null +++ b/MCGalaxy/Games/CTF/CtfGame.Round.cs @@ -0,0 +1,152 @@ +/* + Copyright 2011 MCForge + + Written by fenderrock87 + + Dual-licensed under the Educational Community License, Version 2.0 and + the GNU General Public License, Version 3 (the "Licenses"); you may + not use this file except in compliance with the Licenses. You may + obtain a copy of the Licenses at + + http://www.opensource.org/licenses/ecl2.php + http://www.gnu.org/licenses/gpl-3.0.html + + Unless required by applicable law or agreed to in writing, + software distributed under the Licenses are distributed on an "AS IS" + BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + or implied. See the Licenses for the specific language governing + permissions and limitations under the Licenses. + */ +using System; +using System.Threading; +using MCGalaxy.Maths; +using MCGalaxy.SQL; + +namespace MCGalaxy.Games { + + public sealed partial class CTFGame : RoundsGame { + + protected override void DoRound() { + if (!running) return; + RoundInProgress = true; + + while (Blue.Points < Config.RoundPoints && Red.Points < Config.RoundPoints) { + if (!running) return; + if (!RoundInProgress) break; + Tick(); + } + + if (!running) return; + EndRound(); + Picker.AddRecentMap(Map.MapName); + + // TODO: Move players here + if (RoundsLeft > 0) { + string map = Picker.ChooseNextLevel(this); + // (map != null) ChangeLevel(map); + } + } + + void Tick() { + Player[] online = PlayerInfo.Online.Items; + foreach (Player p in online) { + if (p.level != Map) continue; + + CtfTeam2 team = TeamOf(p); + if (team == null || Get(p).tagging) continue; + if (!OnOwnTeamSide(p.Pos.BlockZ, team)) continue; + CtfTeam2 opposing = Opposing(team); + + Player[] opponents = opposing.Members.Items; + foreach (Player other in opponents) { + if (!MovementCheck.InRange(p, other, 2 * 32)) continue; + + Get(other).tagging = true; + Player.Message(other, p.ColoredName + " %Stagged you!"); + Command.all.FindByName("Spawn").Use(other, ""); + Thread.Sleep(300); + + if (Get(other).hasflag) DropFlag(p, opposing); + Get(p).Points += Config.Tag_PointsGained; + Get(other).Points -= Config.Tag_PointsLost; + Get(p).Tags++; + Get(other).tagging = false; + } + } + } + + public override void EndRound() { + if (!RoundInProgress) return; + RoundInProgress = false; + + if (Blue.Points >= Config.RoundPoints || Blue.Points > Red.Points) { + Chat.MessageLevel(Map, Blue.ColoredName + " %Swon this round of CTF!"); + } else if (Red.Points >= Config.RoundPoints || Red.Points > Blue.Points) { + Chat.MessageLevel(Map, Red.ColoredName + " %Swon this round of CTF!"); + } else { + Chat.MessageLevel(Map, "The round ended in a tie!"); + } + + Thread.Sleep(4000); + //MYSQL! + cache.ForEach(delegate(CtfData d) { + d.hasflag = false; + Database.Backend.UpdateRows("CTF", "Points=@1, Captures=@2, tags=@3", + "WHERE Name = @0", d.p.name, d.Points, d.Captures, d.Tags); + }); + + Picker.AddRecentMap(Map.name); + string nextMap = Picker.ChooseNextLevel(this); + + Chat.MessageLevel(Map, "Starting a new game!"); + Blue.Members.Clear(); + Red.Members.Clear(); + Thread.Sleep(2000); + SetMap(nextMap); + } + + + /// Called when the given player takes the opposing team's flag. + void TakeFlag(Player p, CtfTeam2 team) { + CtfTeam2 opposing = Opposing(team); + Chat.MessageLevel(Map, team.Color + p.DisplayName + " took the " + opposing.ColoredName + " %Steam's FLAG"); + Get(p).hasflag = true; + } + + /// Called when the given player, while holding opposing team's flag, clicks on their own flag. + void ReturnFlag(Player p, CtfTeam2 team) { + Vec3U16 flagPos = team.FlagPos; + p.RevertBlock(flagPos.X, flagPos.Y, flagPos.Z); + p.cancelBlock = true; + + CtfData data = Get(p); + if (data.hasflag) { + Chat.MessageLevel(Map, team.Color + p.DisplayName + " RETURNED THE FLAG!"); + data.hasflag = false; + data.Points += Config.Capture_PointsGained; + data.Captures++; + + CtfTeam2 opposing = Opposing(team); + team.Points++; + flagPos = opposing.FlagPos; + Map.Blockchange(flagPos.X, flagPos.Y, flagPos.Z, opposing.FlagBlock); + } else { + Player.Message(p, "You cannot take your own flag!"); + } + } + + /// Called when the given player drops the opposing team's flag. + void DropFlag(Player p, CtfTeam2 team) { + CtfData data = Get(p); + if (!data.hasflag) return; + + data.hasflag = false; + Chat.MessageLevel(Map, team.Color + p.DisplayName + " DROPPED THE FLAG!"); + data.Points -= Config.Capture_PointsLost; + + CtfTeam2 opposing = Opposing(team); + Vec3U16 pos = opposing.FlagPos; + Map.Blockchange(pos.X, pos.Y, pos.Z, opposing.FlagBlock); + } + } +} diff --git a/MCGalaxy/Games/CTF/CtfGame.cs b/MCGalaxy/Games/CTF/CtfGame.cs index 8ff52bbea..ea3f0142e 100644 --- a/MCGalaxy/Games/CTF/CtfGame.cs +++ b/MCGalaxy/Games/CTF/CtfGame.cs @@ -24,6 +24,7 @@ using System.Threading; using MCGalaxy.Commands.World; using MCGalaxy.Maths; using MCGalaxy.SQL; +using BlockID = System.UInt16; namespace MCGalaxy.Games { @@ -33,35 +34,31 @@ namespace MCGalaxy.Games { public bool hasflag, tagging, TeamChatting; public CtfData(Player p) { this.p = p; } } + + public sealed class CtfTeam2 { + public string Name, Color; + public string ColoredName { get { return Color + Name; } } + public int Points; + public Vec3U16 FlagPos; + public Position SpawnPos; + public BlockID FlagBlock; + public VolatileArray Members = new VolatileArray(); + + public CtfTeam2(string name, string color) { Name = name; Color = color; } + public bool Remove(Player p) { return Members.Remove(p); } + } - public sealed partial class CTFGame : IGame { - public System.Timers.Timer tagging = new System.Timers.Timer(500); - public bool voting = false; - internal int vote1 = 0, vote2 = 0, vote3 = 0; - internal string map1 = "", map2 = "", map3 = ""; - public bool started = false; - - /// Gets whether CTF is currently running. - public override bool Running { get { return started; } } - - public CtfTeam2 Red, Blue; - List cache = new List(); + public sealed partial class CTFGame : RoundsGame { + bool running = false; + public override bool Running { get { return running; } } + public override string GameName { get { return "CTF"; } } + public CtfTeam2 Red = new CtfTeam2("Red", Colors.red); + public CtfTeam2 Blue = new CtfTeam2("Blue", Colors.blue); public CTFConfig Config = new CTFConfig(); - CtfPlugin plugin = new CtfPlugin(); - - /// Create a new CTF object - public CTFGame() { - Red = new CtfTeam2("Red", Colors.red); - Blue = new CtfTeam2("Blue", Colors.blue); - - tagging.Elapsed += CheckTagging; - tagging.Start(); - plugin.Game = this; - plugin.Load(false); - } - - + public LevelPicker Picker = new CTFLevelPicker(); + + List cache = new List(); internal CtfData Get(Player p) { foreach (CtfData d in cache) { if (d.p == p) return d; @@ -72,7 +69,6 @@ namespace MCGalaxy.Games { /// Load a map into CTF public void SetMap(string mapName) { - MapName = mapName; CmdLoad.LoadLevel(null, mapName); Map = LevelInfo.FindExact(mapName); Map.SaveChanges = false; @@ -92,44 +88,7 @@ namespace MCGalaxy.Games { Blue.FlagPos = new Vec3U16((ushort)cfg.BlueFlagX, (ushort)cfg.BlueFlagY, (ushort)cfg.BlueFlagZ); Blue.SpawnPos = new Position(cfg.BlueSpawnX, cfg.BlueSpawnY, cfg.BlueSpawnZ); } - - List GetCtfMaps() { - //Load some configs - if (!Directory.Exists("CTF")) Directory.CreateDirectory("CTF"); - if (!File.Exists("CTF/maps.config")) return new List(); - - string[] lines = File.ReadAllLines("CTF/maps.config"); - return new List(lines); - } - - - void CheckTagging(object sender, System.Timers.ElapsedEventArgs e) { - Player[] online = PlayerInfo.Online.Items; - foreach (Player p in online) { - if (p.level != Map) continue; - - CtfTeam2 team = TeamOf(p); - if (team == null || Get(p).tagging) continue; - if (!OnOwnTeamSide(p.Pos.BlockZ, team)) continue; - CtfTeam2 opposing = Opposing(team); - - Player[] opponents = opposing.Members.Items; - foreach (Player other in opponents) { - if (!MovementCheck.InRange(p, other, 2 * 32)) continue; - Get(other).tagging = true; - Player.Message(other, p.ColoredName + " %Stagged you!"); - Command.all.FindByName("Spawn").Use(other, ""); - Thread.Sleep(300); - - if (Get(other).hasflag) DropFlag(p, opposing); - Get(p).Points += Config.Tag_PointsGained; - Get(other).Points -= Config.Tag_PointsLost; - Get(p).Tags++; - Get(other).tagging = false; - } - } - } static ColumnDesc[] createSyntax = new ColumnDesc[] { new ColumnDesc("ID", ColumnType.Integer, priKey: true, autoInc: true, notNull: true), @@ -141,147 +100,38 @@ namespace MCGalaxy.Games { /// Start the CTF game public bool Start(Player p) { - if (started) { + if (running) { Player.Message(p, "CTF game already running."); return false; } - List maps = GetCtfMaps(); - if (maps.Count == 0) { + List maps = Picker.GetCandidateMaps(); + if (maps == null || maps.Count == 0) { Player.Message(p, "No CTF maps were found."); return false; } Blue = new CtfTeam2("Blue", Colors.blue); - Red = new CtfTeam2("Red", Colors.red); - SetMap(maps[new Random().Next(maps.Count)]); + Red = new CtfTeam2("Red", Colors.red); + SetMap(LevelPicker.GetRandomMap(new Random(), maps)); Logger.Log(LogType.GameActivity, "[CTF] Running..."); - started = true; + running = true; Database.Backend.CreateTable("CTF", createSyntax); + HookEventHandlers(); + + Thread t = new Thread(RunGame); + t.Name = "MCG_CTFGame"; + t.Start(); return true; } - /// Stop the CTF game if running. - public void Stop() { - tagging.Stop(); - tagging.Dispose(); + public override void End() { + running = false; + RoundsLeft = 0; + RoundInProgress = false; + + UnhookEventHandlers(); + Picker.Clear(); Map = null; - started = false; - } - - string Vote() { - started = false; - vote1 = 0; - vote2 = 0; - vote3 = 0; - Random rand = new Random(); - List maps = GetCtfMaps(); - map1 = maps[rand.Next(maps.Count)]; - maps.Remove(map1); - map2 = maps[rand.Next(maps.Count)]; - maps.Remove(map2); - map3 = maps[rand.Next(maps.Count)]; - Chat.MessageLevel(Map, "%2VOTE:"); - Chat.MessageLevel(Map, "1. " + map1 + " 2. " + map2 + " 3. " + map3); - voting = true; - int seconds = rand.Next(15, 61); - Chat.MessageLevel(Map, "You have " + seconds + " seconds to vote!"); - Thread.Sleep(seconds * 1000); - voting = false; - Chat.MessageLevel(Map, "VOTING ENDED!"); - Thread.Sleep(rand.Next(1, 10) * 1000); - if (vote1 > vote2 && vote1 > vote3) - { - Chat.MessageLevel(Map, map1 + " WON!"); - return map1; - } - if (vote2 > vote1 && vote2 > vote3) - { - Chat.MessageLevel(Map, map2 + " WON!"); - return map2; - } - if (vote3 > vote2 && vote3 > vote1) - { - Chat.MessageLevel(Map, map3 + " WON!"); - return map3; - } - else - { - Chat.MessageLevel(Map, "There was a tie!"); - Chat.MessageLevel(Map, "I'll choose!"); - return maps[rand.Next(maps.Count)]; - } - } - - public override void EndRound() { - started = false; - if (Blue.Points >= Config.RoundPoints || Blue.Points > Red.Points) { - Chat.MessageLevel(Map, Blue.ColoredName + " %Swon this round of CTF!"); - } else if (Red.Points >= Config.RoundPoints || Red.Points > Blue.Points) { - Chat.MessageLevel(Map, Red.ColoredName + " %Swon this round of CTF!"); - } else { - Chat.MessageLevel(Map, "The round ended in a tie!"); - } - - Thread.Sleep(4000); - //MYSQL! - cache.ForEach(delegate(CtfData d) { - d.hasflag = false; - Database.Backend.UpdateRows("CTF", "Points=@1, Captures=@2, tags=@3", - "WHERE Name = @0", d.p.name, d.Points, d.Captures, d.Tags); - }); - - string nextmap = Vote(); - Chat.MessageLevel(Map, "Starting a new game!"); - Blue.Members.Clear(); - Red.Members.Clear(); - Thread.Sleep(2000); - SetMap(nextmap); - } - - - /// Called when the given player takes the opposing team's flag. - public void TakeFlag(Player p, CtfTeam2 team) { - CtfTeam2 opposing = Opposing(team); - Chat.MessageLevel(Map, team.Color + p.DisplayName + " took the " + opposing.ColoredName + " %Steam's FLAG"); - Get(p).hasflag = true; - } - - /// Called when the given player, while holding opposing team's flag, clicks on their own flag. - public void ReturnFlag(Player p, CtfTeam2 team) { - Vec3U16 flagPos = team.FlagPos; - p.RevertBlock(flagPos.X, flagPos.Y, flagPos.Z); - p.cancelBlock = true; - - CtfData data = Get(p); - if (data.hasflag) { - Chat.MessageLevel(Map, team.Color + p.DisplayName + " RETURNED THE FLAG!"); - data.hasflag = false; - data.Points += Config.Capture_PointsGained; - data.Captures++; - - CtfTeam2 opposing = Opposing(team); - team.Points++; - flagPos = opposing.FlagPos; - Map.Blockchange(flagPos.X, flagPos.Y, flagPos.Z, opposing.FlagBlock); - - if (team.Points >= Config.RoundPoints) EndRound(); - } else { - Player.Message(p, "You cannot take your own flag!"); - } - } - - /// Called when the given player drops the opposing team's flag. - public void DropFlag(Player p, CtfTeam2 team) { - CtfData data = Get(p); - if (!data.hasflag) return; - - data.hasflag = false; - Chat.MessageLevel(Map, team.Color + p.DisplayName + " DROPPED THE FLAG!"); - data.Points -= Config.Capture_PointsLost; - - CtfTeam2 opposing = Opposing(team); - Vec3U16 pos = opposing.FlagPos; - Map.Blockchange(pos.X, pos.Y, pos.Z, opposing.FlagBlock); } @@ -314,4 +164,22 @@ namespace MCGalaxy.Games { return team == Red ? Blue : Red; } } + + internal class CTFLevelPicker : LevelPicker { + + public override List GetCandidateMaps() { + List maps = null; + if (!Directory.Exists("CTF")) Directory.CreateDirectory("CTF"); + if (File.Exists("CTF/maps.config")) { + string[] lines = File.ReadAllLines("CTF/maps.config"); + maps = new List(lines); + } + + if (maps == null || maps.Count == 0) { + Logger.Log(LogType.Warning, "You must have at least 1 level configured to play CTF"); + return null; + } + return maps; + } + } } diff --git a/MCGalaxy/Games/CTF/CtfTeam.cs b/MCGalaxy/Games/CTF/CtfTeam.cs deleted file mode 100644 index aadd768d4..000000000 --- a/MCGalaxy/Games/CTF/CtfTeam.cs +++ /dev/null @@ -1,57 +0,0 @@ -/* - Copyright 2011 MCForge - - Dual-licensed under the Educational Community License, Version 2.0 and - the GNU General Public License, Version 3 (the "Licenses"); you may - not use this file except in compliance with the Licenses. You may - obtain a copy of the Licenses at - - http://www.opensource.org/licenses/ecl2.php - http://www.gnu.org/licenses/gpl-3.0.html - - Unless required by applicable law or agreed to in writing, - software distributed under the Licenses are distributed on an "AS IS" - BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - or implied. See the Licenses for the specific language governing - permissions and limitations under the Licenses. -*/ -using System; -using MCGalaxy.Maths; -using BlockID = System.UInt16; - -namespace MCGalaxy.Games { - - /// Represents a team in Capture the Flag. - public sealed class CtfTeam2 { - - /// The name of this team. - public string Name; - - /// The color code of this team. - public string Color; - - public string ColoredName { get { return Color + Name; } } - - /// Total points this team has collected. - public int Points; - - /// Players on this team. - public VolatileArray Members = new VolatileArray(); - - - /// Position in the world the flag is located at. - public Vec3U16 FlagPos; - - /// Position in the world members of this team spawn at. - public Position SpawnPos; - - /// Block type of this team's flag. - public BlockID FlagBlock; - - public CtfTeam2(string name, string color) { Name = name; Color = color; } - - - /// Removes a player from this team. - public bool Remove(Player p) { return Members.Remove(p); } - } -} \ No newline at end of file diff --git a/MCGalaxy/Games/Countdown/CountdownPlugin.cs b/MCGalaxy/Games/Countdown/CountdownGame.Plugin.cs similarity index 63% rename from MCGalaxy/Games/Countdown/CountdownPlugin.cs rename to MCGalaxy/Games/Countdown/CountdownGame.Plugin.cs index e06d9e9a3..ac0868b5a 100644 --- a/MCGalaxy/Games/Countdown/CountdownPlugin.cs +++ b/MCGalaxy/Games/Countdown/CountdownGame.Plugin.cs @@ -1,7 +1,7 @@ /* Copyright 2011 MCForge - Dual-licensed under the Educational Community License, Version 2.0 and + Dual-licensed under the Educational Community License, Version 2.0 and the GNU General Public License, Version 3 (the "Licenses"); you may not use this file except in compliance with the Licenses. You may obtain a copy of the Licenses at @@ -20,20 +20,17 @@ using MCGalaxy.Events.LevelEvents; using MCGalaxy.Events.PlayerEvents; namespace MCGalaxy.Games { - public sealed class CountdownPlugin : Plugin_Simple { - public override string creator { get { return Server.SoftwareName + " team"; } } - public override string MCGalaxy_Version { get { return Server.VersionString; } } - public override string name { get { return "Core_CountdownPlugin"; } } - public CountdownGame Game; - - public override void Load(bool startup) { + + public sealed partial class CountdownGame : IGame { + + void HookEventHandlers() { OnPlayerMoveEvent.Register(HandlePlayerMove, Priority.High); OnPlayerDisconnectEvent.Register(HandlePlayerDisconnect, Priority.High); OnLevelUnloadEvent.Register(HandleLevelUnload, Priority.High); OnPlayerSpawningEvent.Register(HandlePlayerSpawning, Priority.High); } - public override void Unload(bool shutdown) { + void UnhookEventHandlers() { OnPlayerMoveEvent.Unregister(HandlePlayerMove); OnPlayerDisconnectEvent.Unregister(HandlePlayerDisconnect); OnLevelUnloadEvent.Unregister(HandleLevelUnload); @@ -42,8 +39,8 @@ namespace MCGalaxy.Games { void HandlePlayerMove(Player p, Position next, byte yaw, byte pitch) { - if (Game.Status != CountdownGameStatus.RoundInProgress || !Game.FreezeMode) return; - if (!Game.Remaining.Contains(p)) return; + if (Status != CountdownGameStatus.RoundInProgress || !FreezeMode) return; + if (!Remaining.Contains(p)) return; if (next.X != p.CountdownFreezeX || next.Z != p.CountdownFreezeZ) { next.X = p.CountdownFreezeX; next.Z = p.CountdownFreezeZ; @@ -56,23 +53,23 @@ namespace MCGalaxy.Games { } void HandlePlayerDisconnect(Player p, string reason) { - if (!Game.Players.Contains(p)) return; + if (!Players.Contains(p)) return; - if (Game.Remaining.Contains(p)) { - Game.Map.ChatLevel(p.ColoredName + " %Slogged out, and so is out of countdown"); - Game.PlayerLeftGame(p); + if (Remaining.Contains(p)) { + Map.ChatLevel(p.ColoredName + " %Slogged out, and so is out of countdown"); + PlayerLeftGame(p); } - Game.Players.Remove(p); + Players.Remove(p); } void HandleLevelUnload(Level lvl) { - if (Game.Status == CountdownGameStatus.Disabled || lvl != Game.Map) return; - Game.Disable(); - } + if (Status == CountdownGameStatus.Disabled || lvl != Map) return; + Disable(); + } void HandlePlayerSpawning(Player p, ref Position pos, ref byte yaw, ref byte pitch, bool respawning) { - if (!respawning || !Game.Remaining.Contains(p)) return; - Game.PlayerDied(p); + if (!respawning || !Remaining.Contains(p)) return; + PlayerDied(p); } } } diff --git a/MCGalaxy/Games/Countdown/CountdownGame.cs b/MCGalaxy/Games/Countdown/CountdownGame.cs index 0e254c99b..afd2f4a1f 100644 --- a/MCGalaxy/Games/Countdown/CountdownGame.cs +++ b/MCGalaxy/Games/Countdown/CountdownGame.cs @@ -19,26 +19,40 @@ using System; using System.Collections.Generic; using System.Threading; using MCGalaxy.Commands.World; +using MCGalaxy.Events; +using MCGalaxy.Events.LevelEvents; +using MCGalaxy.Events.PlayerEvents; using MCGalaxy.Network; using BlockID = System.UInt16; namespace MCGalaxy.Games { - public sealed class CountdownGame : IGame { + + public enum CountdownGameStatus { + /// Countdown is not running. + Disabled, + /// Countdown is running, but no round has begun yet. + Enabled, + /// Timer is counting down to start of round. + RoundCountdown, + /// Round is in progress. + RoundInProgress, + } + + public sealed partial class CountdownGame : IGame { public VolatileArray Players = new VolatileArray(); public VolatileArray Remaining = new VolatileArray(); - public CountdownGameStatus Status = CountdownGameStatus.Disabled; + public CountdownGameStatus Status = CountdownGameStatus.Disabled; public override bool Running { get { return Status != CountdownGameStatus.Disabled; } } + public override string GameName { get { return "Countdown"; } } - public bool FreezeMode = false; + public bool FreezeMode; public int Interval; public string SpeedType; - CountdownPlugin plugin = new CountdownPlugin(); List squaresLeft = new List(); BufferedBlockSender bulk = new BufferedBlockSender(); - public override void EndRound() { EndRound(null); } @@ -70,23 +84,23 @@ namespace MCGalaxy.Games { SpawnPlayers(xSpawn, ySpawn, zSpawn); Map.ChatLevel("-----&b5%S-----"); - if (Status != CountdownGameStatus.RoundCountdown) return; + if (Status != CountdownGameStatus.RoundCountdown) return; Cuboid(midX - 1, midY, midZ - 1, midX, midY, midZ, Block.Air); bulk.Send(true); Thread.Sleep(1000); - if (Status != CountdownGameStatus.RoundCountdown) return; + if (Status != CountdownGameStatus.RoundCountdown) return; Map.ChatLevel("-----&b4%S-----"); Thread.Sleep(1000); Map.ChatLevel("-----&b3%S-----"); Thread.Sleep(1000); Cuboid(midX, Map.Height - 5, midZ, midX + 1, Map.Height - 5, midZ + 1, Block.Air); bulk.Send(true); - if (Status != CountdownGameStatus.RoundCountdown) return; + if (Status != CountdownGameStatus.RoundCountdown) return; Map.ChatLevel("-----&b2%S-----"); Thread.Sleep(1000); Map.ChatLevel("-----&b1%S-----"); Thread.Sleep(1000); Map.ChatLevel("GO!!!!!!!"); - if (Status != CountdownGameStatus.RoundCountdown) return; + if (Status != CountdownGameStatus.RoundCountdown) return; Player[] players = Players.Items; Remaining.Clear(); foreach (Player pl in players) { Remaining.Add(pl); } @@ -323,10 +337,7 @@ namespace MCGalaxy.Games { public void Enable(Player p) { - plugin.Game = this; - plugin.Load(false); - - MapName = "countdown"; + HookEventHandlers(); CmdLoad.LoadLevel(null, "countdown"); Map = LevelInfo.FindExact("countdown"); @@ -347,10 +358,9 @@ namespace MCGalaxy.Games { } public void Disable() { - if (Status == CountdownGameStatus.RoundInProgress) EndRound(null); - + if (Status == CountdownGameStatus.RoundInProgress) EndRound(null); Status = CountdownGameStatus.Disabled; - plugin.Unload(false); + UnhookEventHandlers(); Map.ChatLevel("Countdown was disabled."); Players.Clear(); @@ -397,11 +407,11 @@ namespace MCGalaxy.Games { Cuboid(midX - 1, midY + 1, midZ + 1, midX, midY + 2, midZ + 1, block); Cuboid(midX - 2, midY + 1, midZ - 1, midX - 2, midY + 2, midZ, block); Cuboid(midX + 1, midY + 1, midZ - 1, midX + 1, midY + 2, midZ, block); - Cuboid(midX - 1, midY, midZ - 1, midX, midY, midZ, floorBlock); + Cuboid(midX - 1, midY, midZ - 1, midX, midY, midZ, floorBlock); bulk.Send(true); } - void Cuboid(int x1, int y1, int z1, int x2, int y2, int z2, BlockID block) { + void Cuboid(int x1, int y1, int z1, int x2, int y2, int z2, BlockID block) { for (int y = y1; y <= y2; y++) for (int z = z1; z <= z2; z++) for (int x = x1; x <= x2; x++) @@ -437,18 +447,4 @@ namespace MCGalaxy.Games { UpdatePlayersLeft(); } } - - public enum CountdownGameStatus { - /// Countdown is not running. - Disabled, - - /// Countdown is running, but no round has begun yet. - Enabled, - - /// Timer is counting down to start of round. - RoundCountdown, - - /// Round is in progress. - RoundInProgress, - } } diff --git a/MCGalaxy/Games/GameProps.cs b/MCGalaxy/Games/GameProps.cs index d7f39db4c..d53d3de94 100644 --- a/MCGalaxy/Games/GameProps.cs +++ b/MCGalaxy/Games/GameProps.cs @@ -60,9 +60,6 @@ namespace MCGalaxy.Games { /// Whether the real names of zombies are always shown to the player. public bool Aka = false; - /// Last name color sent to other players from a call to GlobalSpawn. - internal string lastSpawnColor = ""; - /// List of custom infect messages this player has. internal List InfectMessages = null; diff --git a/MCGalaxy/Games/IGame.cs b/MCGalaxy/Games/IGame.cs index e2b70c8ee..451a44da4 100644 --- a/MCGalaxy/Games/IGame.cs +++ b/MCGalaxy/Games/IGame.cs @@ -20,32 +20,34 @@ using System; namespace MCGalaxy.Games { public abstract class IGame { - public string MapName; public Level Map; public abstract bool Running { get; } - - /// Whether players are allowed to teleport to others when not in referee mode. + public abstract string GameName { get; } public virtual bool TeleportAllowed { get { return true; } } - /// Returns whether this game handled the player sending a chat message. - public virtual bool HandlesChatMessage(Player p, string message) { return false; } - - public virtual void PlayerJoinedServer(Player p) { } + + public virtual bool HandlesChatMessage(Player p, string message) { return false; } public virtual void PlayerJoinedGame(Player p) { } public virtual void PlayerLeftGame(Player p) { } public virtual void PlayerJoinedLevel(Player p, Level lvl, Level oldLvl) { } - public virtual void OnHeartbeat(ref string name) { } - - /// Adjusts the prefix (e.g. title) shown before the player's name in chat. - public virtual void AdjustPrefix(Player p, ref string prefix) { } + public virtual void AdjustPrefix(Player p, ref string prefix) { } public abstract void EndRound(); + + public void MessageMap(CpeMessageType type, string message) { + if (!Running) return; + Player[] online = PlayerInfo.Online.Items; + + foreach (Player p in online) { + if (p.level != Map) continue; + p.SendCpeMessage(type, message); + } + } } public abstract class RoundsGame : IGame { public int RoundsLeft; public bool RoundInProgress; - public abstract string GameName { get; } public abstract void End(); protected abstract void DoRound(); diff --git a/MCGalaxy/Games/LavaSurvival/LavaSurvival.Settings.cs b/MCGalaxy/Games/LavaSurvival/LSConfig.cs similarity index 78% rename from MCGalaxy/Games/LavaSurvival/LavaSurvival.Settings.cs rename to MCGalaxy/Games/LavaSurvival/LSConfig.cs index 134971a12..cb8ba5956 100644 --- a/MCGalaxy/Games/LavaSurvival/LavaSurvival.Settings.cs +++ b/MCGalaxy/Games/LavaSurvival/LSConfig.cs @@ -23,15 +23,15 @@ using MCGalaxy.Maths; using BlockID = System.UInt16; namespace MCGalaxy.Games { - public sealed partial class LavaSurvival { + public sealed partial class LSGame : RoundsGame { public MapData GenerateMapData(MapSettings settings) { MapData data = new MapData(settings); - data.killer = rand.Next(1, 101) <= settings.killer; + data.killer = rand.Next(1, 101) <= settings.killer; data.destroy = rand.Next(1, 101) <= settings.destroy; - data.water = rand.Next(1, 101) <= settings.water; - data.layer = rand.Next(1, 101) <= settings.layer; - data.fast = rand.Next(1, 101) <= settings.fast && !data.water; + data.water = rand.Next(1, 101) <= settings.water; + data.layer = rand.Next(1, 101) <= settings.layer; + data.fast = rand.Next(1, 101) <= settings.fast && !data.water; byte block = data.water ? (data.killer ? Block.Deadly_ActiveWater : Block.Water) : (data.fast ? (data.killer ? Block.Deadly_FastLava : Block.FastLava) @@ -99,8 +99,8 @@ namespace MCGalaxy.Games { public MapSettings LoadMapSettings(string name) { MapSettings settings = new MapSettings(name); - if (!Directory.Exists(propsPath)) Directory.CreateDirectory(propsPath); - string path = propsPath + name + ".properties"; + if (!Directory.Exists(propsDir)) Directory.CreateDirectory(propsDir); + string path = propsDir + name + ".properties"; if (!File.Exists(path)) { SaveMapSettings(settings); return settings; } try { @@ -112,55 +112,47 @@ namespace MCGalaxy.Games { } void ProcessMapLine(string key, string value, ref MapSettings map) { - string[] sp; switch (key.ToLower()) { case "fast-chance": map.fast = (byte)Utils.Clamp(int.Parse(value), 0, 100); break; case "killer-chance": map.killer = (byte)Utils.Clamp(int.Parse(value), 0, 100); break; case "destroy-chance": map.destroy = (byte)Utils.Clamp(int.Parse(value), 0, 100); break; case "water-chance": map.water = (byte)Utils.Clamp(int.Parse(value), 0, 100); break; case "layer-chance": map.layer = (byte)Utils.Clamp(int.Parse(value), 0, 100); break; - case "layer-height": map.layerHeight = int.Parse(value); break; - case "layer-count": map.layerCount = int.Parse(value); break; + case "layer-height": map.LayerHeight = int.Parse(value); break; + case "layer-count": map.LayerCount = int.Parse(value); break; case "layer-interval": map.layerInterval = double.Parse(value); break; case "round-time": map.roundTime = double.Parse(value); break; case "flood-time": map.floodTime = double.Parse(value); break; case "block-flood": - sp = value.Split(','); - map.blockFlood = new Vec3U16(ushort.Parse(sp[0]), ushort.Parse(sp[1]), ushort.Parse(sp[2])); - break; + map.FloodPos = Vec3U16.Parse(value); break; case "block-layer": - sp = value.Split(','); - map.blockLayer = new Vec3U16(ushort.Parse(sp[0]), ushort.Parse(sp[1]), ushort.Parse(sp[2])); - break; + map.LayerPos = Vec3U16.Parse(value); break; case "safe-zone": - sp = value.Split('-'); - string[] p1 = sp[0].Split(','), p2 = sp[1].Split(','); - map.safeZone = new Vec3U16[] { - new Vec3U16(ushort.Parse(p1[0]), ushort.Parse(p1[1]), ushort.Parse(p1[2])), - new Vec3U16(ushort.Parse(p2[0]), ushort.Parse(p2[1]), ushort.Parse(p2[2])) }; + string[] p = value.Split('-'); + map.safeZone = new Vec3U16[] { Vec3U16.Parse(p[0]), Vec3U16.Parse(p[1]) }; break; } } public void SaveMapSettings(MapSettings settings) { - if (!Directory.Exists(propsPath)) Directory.CreateDirectory(propsPath); + if (!Directory.Exists(propsDir)) Directory.CreateDirectory(propsDir); - using (StreamWriter w = new StreamWriter(propsPath + settings.name + ".properties")) { + using (StreamWriter w = new StreamWriter(propsDir + settings.name + ".properties")) { w.WriteLine("#Lava Survival properties for " + settings.name); w.WriteLine("fast-chance = " + settings.fast); w.WriteLine("killer-chance = " + settings.killer); w.WriteLine("destroy-chance = " + settings.destroy); w.WriteLine("water-chance = " + settings.water); w.WriteLine("layer-chance = " + settings.layer); - w.WriteLine("layer-height = " + settings.layerHeight); - w.WriteLine("layer-count = " + settings.layerCount); + w.WriteLine("layer-height = " + settings.LayerHeight); + w.WriteLine("layer-count = " + settings.LayerCount); w.WriteLine("layer-interval = " + settings.layerInterval); w.WriteLine("round-time = " + settings.roundTime); w.WriteLine("flood-time = " + settings.floodTime); - w.WriteLine("block-flood = " + settings.blockFlood); - w.WriteLine("block-layer = " + settings.blockLayer); - w.WriteLine(String.Format("safe-zone = {0}-{1}", settings.safeZone[0].ToString(), settings.safeZone[1].ToString())); + w.WriteLine("block-flood = " + settings.FloodPos); + w.WriteLine("block-layer = " + settings.LayerPos); + w.WriteLine("safe-zone = " + settings.safeZone[0] + " - " + settings.safeZone[1]); } } @@ -169,9 +161,9 @@ namespace MCGalaxy.Games { { public string name; public byte fast, killer, destroy, water, layer; - public int layerHeight, layerCount; + public int LayerHeight, LayerCount; public double layerInterval, roundTime, floodTime; - public Vec3U16 blockFlood, blockLayer; + public Vec3U16 FloodPos, LayerPos; public Vec3U16[] safeZone; public MapSettings(string name) @@ -182,13 +174,13 @@ namespace MCGalaxy.Games { destroy = 0; water = 0; layer = 0; - layerHeight = 3; - layerCount = 10; + LayerHeight = 3; + LayerCount = 10; layerInterval = 2; roundTime = 15; floodTime = 5; - blockFlood = new Vec3U16(); - blockLayer = new Vec3U16(); + FloodPos = new Vec3U16(); + LayerPos = new Vec3U16(); safeZone = new Vec3U16[2]; } } diff --git a/MCGalaxy/Games/LavaSurvival/LSGame.Plugin.cs b/MCGalaxy/Games/LavaSurvival/LSGame.Plugin.cs new file mode 100644 index 000000000..ccefb9dd1 --- /dev/null +++ b/MCGalaxy/Games/LavaSurvival/LSGame.Plugin.cs @@ -0,0 +1,60 @@ +/* + Copyright 2011 MCForge + + Dual-licensed under the Educational Community License, Version 2.0 and + the GNU General Public License, Version 3 (the "Licenses"); you may + not use this file except in compliance with the Licenses. You may + obtain a copy of the Licenses at + + http://www.opensource.org/licenses/ecl2.php + http://www.gnu.org/licenses/gpl-3.0.html + + Unless required by applicable law or agreed to in writing, + software distributed under the Licenses are distributed on an "AS IS" + BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + or implied. See the Licenses for the specific language governing + permissions and limitations under the Licenses. + */ +using System; +using MCGalaxy.Events; +using MCGalaxy.Events.PlayerEvents; +using MCGalaxy.Events.LevelEvents; +using BlockID = System.UInt16; + +namespace MCGalaxy.Games { + public sealed partial class LSGame : RoundsGame { + + void HookEventHandlers() { + OnLevelUnloadEvent.Register(HandleLevelUnload, Priority.High); + + OnPlayerConnectEvent.Register(HandlePlayerConnect, Priority.High); + OnPlayerDeathEvent.Register(HandlePlayerDeath, Priority.High); + } + + void UnhookEventHandlers() { + OnLevelUnloadEvent.Unregister(HandleLevelUnload); + + OnPlayerConnectEvent.Unregister(HandlePlayerConnect); + OnPlayerDeathEvent.Unregister(HandlePlayerDeath); + } + + + void HandleLevelUnload(Level lvl) { + if (lvl == Map) lvl.cancelunload = true; + } + + void HandlePlayerConnect(Player p) { + Player.Message(p, "&cLava Survival %Sis running! Type %T/ls go %Sto join"); + } + + void HandlePlayerDeath(Player p, BlockID block) { + if (p.level != Map) return; + + if (IsPlayerDead(p)) { + p.cancelDeath = true; + } else { + KillPlayer(p); + } + } + } +} diff --git a/MCGalaxy/Games/LavaSurvival/LavaSurvival.cs b/MCGalaxy/Games/LavaSurvival/LSGame.Round.cs similarity index 53% rename from MCGalaxy/Games/LavaSurvival/LavaSurvival.cs rename to MCGalaxy/Games/LavaSurvival/LSGame.Round.cs index 53aee273b..e924e5887 100644 --- a/MCGalaxy/Games/LavaSurvival/LavaSurvival.cs +++ b/MCGalaxy/Games/LavaSurvival/LSGame.Round.cs @@ -1,426 +1,291 @@ -/* - Copyright 2011 MCForge - - Dual-licensed under the Educational Community License, Version 2.0 and - the GNU General Public License, Version 3 (the "Licenses"); you may - not use this file except in compliance with the Licenses. You may - obtain a copy of the Licenses at - - http://www.opensource.org/licenses/ecl2.php - http://www.gnu.org/licenses/gpl-3.0.html - - Unless required by applicable law or agreed to in writing, - software distributed under the Licenses are distributed on an "AS IS" - BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - or implied. See the Licenses for the specific language governing - permissions and limitations under the Licenses. -*/ +/* + Copyright 2011 MCForge + + Dual-licensed under the Educational Community License, Version 2.0 and + the GNU General Public License, Version 3 (the "Licenses"); you may + not use this file except in compliance with the Licenses. You may + obtain a copy of the Licenses at + + http://www.opensource.org/licenses/ecl2.php + http://www.gnu.org/licenses/gpl-3.0.html + + Unless required by applicable law or agreed to in writing, + software distributed under the Licenses are distributed on an "AS IS" + BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + or implied. See the Licenses for the specific language governing + permissions and limitations under the Licenses. +*/ using System; using System.Collections.Generic; using System.Text; using System.Timers; using MCGalaxy.Commands.World; -using MCGalaxy.Maths; - -namespace MCGalaxy.Games -{ - public sealed partial class LavaSurvival - { - // Private variables - private string propsPath = "properties/lavasurvival/"; - private List maps, voted; - private Dictionary votes, deaths; - private Random rand = new Random(); - private Timer announceTimer, voteTimer, transferTimer; - private DateTime startTime; - - // Public variables - public bool active = false, roundActive = false, flooded = false, voteActive = false, sendingPlayers = false; - public Level map; - public MapSettings mapSettings; - public MapData mapData; - - /// Gets whether lava survival is currently running. - public override bool Running { get { return active; } } - - // Settings - public bool startOnStartup, sendAfkMain = true; - public byte voteCount = 2; - public int lifeNum = 3; - public double voteTime = 2; - - // Constructors - public LavaSurvival() { - maps = new List(); - voted = new List(); - votes = new Dictionary(); - deaths = new Dictionary(); - announceTimer = new Timer(60000); - announceTimer.AutoReset = true; - announceTimer.Elapsed += delegate - { - if (!flooded) AnnounceTimeLeft(true, false); - }; - LoadSettings(); - } - - // Public methods - public byte Start(string mapName = "") - { - if (active) return 1; // Already started - if (maps.Count < 3) return 2; // Not enough maps - if (!String.IsNullOrEmpty(mapName) && !HasMap(mapName)) return 3; // Map doesn't exist - - deaths.Clear(); - active = true; - Logger.Log(LogType.GameActivity, "[Lava Survival] Game started."); - - try { LoadMap(String.IsNullOrEmpty(mapName) ? maps[rand.Next(maps.Count)] : mapName); } - catch (Exception e) { Logger.LogError(e); active = false; return 4; } - return 0; - } - public byte Stop() - { - if (!active) return 1; // Not started - - active = false; - roundActive = false; - voteActive = false; - flooded = false; - deaths.Clear(); - if (announceTimer.Enabled) announceTimer.Stop(); - try { mapData.Dispose(); } - catch { } - try { voteTimer.Dispose(); } - catch { } - try { transferTimer.Dispose(); } - catch { } - map.Unload(true, false); - map = null; - Logger.Log(LogType.GameActivity, "[Lava Survival] Game stopped."); - return 0; - } - - public void StartRound() - { - if (roundActive) return; - - try - { - deaths.Clear(); - mapData.roundTimer.Elapsed += delegate { EndRound(); }; - mapData.floodTimer.Elapsed += delegate { DoFlood(); }; - mapData.roundTimer.Start(); - mapData.floodTimer.Start(); - announceTimer.Start(); - startTime = DateTime.UtcNow; - roundActive = true; - Logger.Log(LogType.GameActivity, "[Lava Survival] Round started. Map: " + map.ColoredName); - } - catch (Exception e) { Logger.LogError(e); } - } - - public override void EndRound() - { - if (!roundActive) return; - - roundActive = false; - flooded = false; - try - { - try { mapData.Dispose(); } - catch { } - map.SetPhysics(5); - map.ChatLevel("The round has ended!"); - Logger.Log(LogType.GameActivity, "[Lava Survival] Round ended. Voting..."); - StartVote(); - } - catch (Exception e) { Logger.LogError(e); } - } - - public void DoFlood() - { - if (!active || !roundActive || flooded || map == null) return; - flooded = true; - - try - { - announceTimer.Stop(); - map.ChatLevel("&4Look out, here comes the flood!"); - Logger.Log(LogType.GameActivity, "[Lava Survival] Map flooding."); - if (mapData.layer) - { - DoFloodLayer(); - mapData.layerTimer.Elapsed += delegate - { - if (mapData.currentLayer <= mapSettings.layerCount) - { - DoFloodLayer(); - } - else - mapData.layerTimer.Stop(); - }; - mapData.layerTimer.Start(); - } - else - { - map.Blockchange(mapSettings.blockFlood.X, mapSettings.blockFlood.Y, mapSettings.blockFlood.Z, mapData.block, true); - } - } - catch (Exception e) { Logger.LogError(e); } - } - - void DoFloodLayer() { - Logger.Log(LogType.GameActivity, "[Lava Survival] Layer " + mapData.currentLayer + " flooding."); - map.Blockchange(mapSettings.blockLayer.X, (ushort)(mapSettings.blockLayer.Y + ((mapSettings.layerHeight * mapData.currentLayer) - 1)), mapSettings.blockLayer.Z, mapData.block, true); - mapData.currentLayer++; - } - - public void AnnounceTimeLeft(bool flood, bool round, Player p = null, bool console = false) { - if (!active || !roundActive || startTime == null || map == null) return; - - if (flood) { - double floodMinutes = Math.Ceiling((startTime.AddMinutes(mapSettings.floodTime) - DateTime.UtcNow).TotalMinutes); - if (p == null && !console) map.ChatLevel("&3" + floodMinutes + " minute" + (floodMinutes == 1 ? "" : "s") + " %Suntil the flood."); - else Player.Message(p, "&3" + floodMinutes + " minute" + (floodMinutes == 1 ? "" : "s") + " %Suntil the flood."); - } - if (round) { - double roundMinutes = Math.Ceiling((startTime.AddMinutes(mapSettings.roundTime) - DateTime.UtcNow).TotalMinutes); - if (p == null && !console) map.ChatLevel("&3" + roundMinutes + " minute" + (roundMinutes == 1 ? "" : "s") + " %Suntil the round ends."); - else Player.Message(p, "&3" + roundMinutes + " minute" + (roundMinutes == 1 ? "" : "s") + " %Suntil the round ends."); - } - } - - public void AnnounceRoundInfo(Player p = null, bool console = false) { - if (p == null && !console) { - if (mapData.water) map.ChatLevel("The map will be flooded with &9water %Sthis round!"); - if (mapData.layer) - { - map.ChatLevel("The " + (mapData.water ? "water" : "lava") + " will &aflood in layers %Sthis round!"); - map.ChatLevelOps("There will be " + mapSettings.layerCount + " layers, each " + mapSettings.layerHeight + " blocks high."); - map.ChatLevelOps("There will be another layer every " + mapSettings.layerInterval + " minutes."); - } - if (mapData.fast) map.ChatLevel("The lava will be &cfast %Sthis round!"); - if (mapData.killer) map.ChatLevel("The " + (mapData.water ? "water" : "lava") + " will &ckill you %Sthis round!"); - if (mapData.destroy) map.ChatLevel("The " + (mapData.water ? "water" : "lava") + " will &cdestroy plants " + (mapData.water ? "" : "and flammable blocks ") + "%Sthis round!"); - } else { - if (mapData.water) Player.Message(p, "The map will be flooded with &9water %Sthis round!"); - if (mapData.layer) Player.Message(p, "The " + (mapData.water ? "water" : "lava") + " will &aflood in layers %Sthis round!"); - if (mapData.fast) Player.Message(p, "The lava will be &cfast %Sthis round!"); - if (mapData.killer) Player.Message(p, "The " + (mapData.water ? "water" : "lava") + " will &ckill you %Sthis round!"); - if (mapData.destroy) Player.Message(p, "The " + (mapData.water ? "water" : "lava") + " will &cdestroy plants " + (mapData.water ? "" : "and flammable blocks ") + "%Sthis round!"); - } - } - - public void LoadMap(string name) - { - if (String.IsNullOrEmpty(name) || !HasMap(name)) return; - - name = name.ToLower(); - Level oldMap = null; - if (active && map != null) oldMap = map; - CmdLoad.LoadLevel(null, name); - map = LevelInfo.FindExact(name); - - if (map != null) - { - mapSettings = LoadMapSettings(name); - mapData = GenerateMapData(mapSettings); - map.SaveChanges = false; - - map.SetPhysics(mapData.destroy ? 2 : 1); - map.Config.PhysicsOverload = 1000000; - map.Config.AutoUnload = false; - map.Config.LoadOnGoto = false; - Level.SaveSettings(map); - } - - if (active && map != null) - { - sendingPlayers = true; - try - { - Player[] online = PlayerInfo.Online.Items; - foreach (Player pl in online) { - pl.Game.RatedMap = false; - pl.Game.PledgeSurvive = false; - if (pl.level == oldMap) - { - if (sendAfkMain && pl.IsAfk) - PlayerActions.ChangeMap(pl, Server.mainLevel); - else - PlayerActions.ChangeMap(pl, map); - } - } - oldMap.Unload(true, false); - } - catch { } - sendingPlayers = false; - - StartRound(); - } - } - - public void StartVote() - { - if (maps.Count < 3) return; - - // Make sure these are cleared or bad stuff happens! - votes.Clear(); - voted.Clear(); - - byte i = 0; - string opt, str = ""; - while (i < Math.Min(voteCount, maps.Count - 1)) - { - opt = maps[rand.Next(maps.Count)]; - if (!votes.ContainsKey(opt) && opt != map.name) - { - votes.Add(opt, 0); - str += "%S, &5" + opt.Capitalize(); - i++; - } - } - - map.ChatLevel("Vote for the next map! The vote ends in " + voteTime + " minute" + (voteTime == 1 ? "" : "s") +"."); - map.ChatLevel("Choices: " + str.Remove(0, 4)); - - voteTimer = new Timer(TimeSpan.FromMinutes(voteTime).TotalMilliseconds); - voteTimer.AutoReset = false; - voteTimer.Elapsed += delegate - { - try { - EndVote(); - voteTimer.Dispose(); - } - catch (Exception e) { Logger.LogError(e); } - }; - voteTimer.Start(); - voteActive = true; - } - - List GetVotedLevels() { - var keys = votes.Keys; - List names = new List(); - foreach (string key in keys) - names.Add(key); - return names; - } - - public void EndVote() { - if (!voteActive) return; - - voteActive = false; - Logger.Log(LogType.GameActivity, "[Lava Survival] Vote ended."); - KeyValuePair most = new KeyValuePair(String.Empty, -1); - foreach (KeyValuePair kvp in votes) - { - if (kvp.Value > most.Value) most = kvp; - map.ChatLevelOps("&5" + kvp.Key.Capitalize() + "&f: &a" + kvp.Value); - } - votes.Clear(); - voted.Clear(); - - map.ChatLevel("The vote has ended! &5" + most.Key.Capitalize() + " %Swon with &a" + most.Value + " %Svote" + (most.Value == 1 ? "" : "s") + "."); - map.ChatLevel("You will be transferred in 5 seconds..."); - transferTimer = new Timer(5000); - transferTimer.AutoReset = false; - transferTimer.Elapsed += delegate - { - try - { - LoadMap(most.Key); - transferTimer.Dispose(); - } - catch (Exception e) { Logger.LogError(e); } - }; - transferTimer.Start(); - } - - public bool AddVote(Player p, string vote) - { - if (!voteActive || voted.Contains(p.name) || !votes.ContainsKey(vote)) return false; - int temp = votes[vote] + 1; - votes.Remove(vote); - votes.Add(vote, temp); - voted.Add(p.name); - return true; - } - - public bool HasVote(string vote) - { - return voteActive && votes.ContainsKey(vote); - } - - public bool HasPlayer(Player p) - { - return p.level == map; - } - public void KillPlayer(Player p, bool silent = false) - { - if (lifeNum < 1) return; - string name = p.name.ToLower(); - if (!deaths.ContainsKey(name)) - deaths.Add(name, 0); - deaths[name]++; - - if (!silent && IsPlayerDead(p)) - { - Player[] online = PlayerInfo.Online.Items; - foreach (Player pl in online) { - if (pl != p && HasPlayer(pl)) - Player.Message(pl, p.ColoredName + " &4ran out of lives, and is out of the round!"); - } - Player.Message(p, "&4You ran out of lives, and are out of the round!"); - Player.Message(p, "&4You can still watch, but you cannot build."); - } - } - public bool IsPlayerDead(Player p) - { - string name = p.name.ToLower(); - if (lifeNum < 1 || !deaths.ContainsKey(name)) - return false; - return (deaths[name] >= lifeNum); - } - - public void AddMap(string name) - { - if (!String.IsNullOrEmpty(name) && !HasMap(name)) - { - maps.Add(name.ToLower()); - SaveSettings(); - } - } - public void RemoveMap(string name) - { - if (maps.CaselessRemove(name)) - { - SaveSettings(); - } - } - public bool HasMap(string name) - { - return maps.CaselessContains(name); - } - - public bool InSafeZone(Vec3U16 pos) - { - return InSafeZone(pos.X, pos.Y, pos.Z); - } - - public bool InSafeZone(ushort x, ushort y, ushort z) - { - if (mapSettings == null) return false; - return x >= mapSettings.safeZone[0].X && x <= mapSettings.safeZone[1].X && y >= mapSettings.safeZone[0].Y - && y <= mapSettings.safeZone[1].Y && z >= mapSettings.safeZone[0].Z && z <= mapSettings.safeZone[1].Z; - } - - public List Maps - { - get - { - return new List(maps); - } - } - } -} +using MCGalaxy.Maths; + +namespace MCGalaxy.Games { + public sealed partial class LSGame : RoundsGame { + + public void StartRound() { + if (roundActive) return; + + try { + deaths.Clear(); + mapData.roundTimer.Elapsed += delegate { EndRound(); }; + mapData.floodTimer.Elapsed += delegate { DoFlood(); }; + mapData.roundTimer.Start(); + mapData.floodTimer.Start(); + announceTimer.Start(); + startTime = DateTime.UtcNow; + roundActive = true; + Logger.Log(LogType.GameActivity, "[Lava Survival] Round started. Map: " + Map.ColoredName); + } + catch (Exception e) { Logger.LogError(e); } + } + + protected override void DoRound() { + if (!running) return; + } + + // RTound format + // announce / round countdown + // flood / flood layers + // vote for next + + public override void EndRound() { + if (!roundActive) return; + + roundActive = false; + flooded = false; + + try { + try { mapData.Dispose(); } + catch { } + Map.SetPhysics(5); + Map.ChatLevel("The round has ended!"); + Logger.Log(LogType.GameActivity, "[Lava Survival] Round ended. Voting..."); + StartVote(); + } + catch (Exception e) { Logger.LogError(e); } + } + + public void DoFlood() + { + if (!running || !roundActive || flooded || Map == null) return; + flooded = true; + + try + { + announceTimer.Stop(); + Map.ChatLevel("&4Look out, here comes the flood!"); + Logger.Log(LogType.GameActivity, "[Lava Survival] Map flooding."); + if (mapData.layer) + { + DoFloodLayer(); + mapData.layerTimer.Elapsed += delegate + { + if (mapData.currentLayer <= mapSettings.LayerCount) + { + DoFloodLayer(); + } + else + mapData.layerTimer.Stop(); + }; + mapData.layerTimer.Start(); + } + else + { + Map.Blockchange(mapSettings.FloodPos.X, mapSettings.FloodPos.Y, mapSettings.FloodPos.Z, mapData.block, true); + } + } + catch (Exception e) { Logger.LogError(e); } + } + + void DoFloodLayer() { + Logger.Log(LogType.GameActivity, "[Lava Survival] Layer " + mapData.currentLayer + " flooding."); + Map.Blockchange(mapSettings.LayerPos.X, (ushort)(mapSettings.LayerPos.Y + ((mapSettings.LayerHeight * mapData.currentLayer) - 1)), mapSettings.LayerPos.Z, mapData.block, true); + mapData.currentLayer++; + } + + public void AnnounceTimeLeft(bool flood, bool round, Player p = null, bool console = false) { + if (!running || !roundActive || startTime == null || Map == null) return; + + if (flood) { + double floodMinutes = Math.Ceiling((startTime.AddMinutes(mapSettings.floodTime) - DateTime.UtcNow).TotalMinutes); + if (p == null && !console) Map.ChatLevel("&3" + floodMinutes + " minute" + (floodMinutes == 1 ? "" : "s") + " %Suntil the flood."); + else Player.Message(p, "&3" + floodMinutes + " minute" + (floodMinutes == 1 ? "" : "s") + " %Suntil the flood."); + } + if (round) { + double roundMinutes = Math.Ceiling((startTime.AddMinutes(mapSettings.roundTime) - DateTime.UtcNow).TotalMinutes); + if (p == null && !console) Map.ChatLevel("&3" + roundMinutes + " minute" + (roundMinutes == 1 ? "" : "s") + " %Suntil the round ends."); + else Player.Message(p, "&3" + roundMinutes + " minute" + (roundMinutes == 1 ? "" : "s") + " %Suntil the round ends."); + } + } + + public void AnnounceRoundInfo(Player p = null, bool console = false) { + if (p == null && !console) { + if (mapData.water) Map.ChatLevel("The map will be flooded with &9water %Sthis round!"); + if (mapData.layer) + { + Map.ChatLevel("The " + (mapData.water ? "water" : "lava") + " will &aflood in layers %Sthis round!"); + Map.ChatLevelOps("There will be " + mapSettings.LayerCount + " layers, each " + mapSettings.LayerHeight + " blocks high."); + Map.ChatLevelOps("There will be another layer every " + mapSettings.layerInterval + " minutes."); + } + if (mapData.fast) Map.ChatLevel("The lava will be &cfast %Sthis round!"); + if (mapData.killer) Map.ChatLevel("The " + (mapData.water ? "water" : "lava") + " will &ckill you %Sthis round!"); + if (mapData.destroy) Map.ChatLevel("The " + (mapData.water ? "water" : "lava") + " will &cdestroy plants " + (mapData.water ? "" : "and flammable blocks ") + "%Sthis round!"); + } else { + if (mapData.water) Player.Message(p, "The map will be flooded with &9water %Sthis round!"); + if (mapData.layer) Player.Message(p, "The " + (mapData.water ? "water" : "lava") + " will &aflood in layers %Sthis round!"); + if (mapData.fast) Player.Message(p, "The lava will be &cfast %Sthis round!"); + if (mapData.killer) Player.Message(p, "The " + (mapData.water ? "water" : "lava") + " will &ckill you %Sthis round!"); + if (mapData.destroy) Player.Message(p, "The " + (mapData.water ? "water" : "lava") + " will &cdestroy plants " + (mapData.water ? "" : "and flammable blocks ") + "%Sthis round!"); + } + } + + public void LoadMap(string name) + { + if (String.IsNullOrEmpty(name) || !HasMap(name)) return; + + name = name.ToLower(); + Level oldMap = null; + if (running && Map != null) oldMap = Map; + CmdLoad.LoadLevel(null, name); + Map = LevelInfo.FindExact(name); + + if (Map != null) { + mapSettings = LoadMapSettings(name); + mapData = GenerateMapData(mapSettings); + Map.SaveChanges = false; + + Map.SetPhysics(mapData.destroy ? 2 : 1); + Map.Config.PhysicsOverload = 1000000; + Map.Config.LoadOnGoto = false; + Level.SaveSettings(Map); + } + + if (running && Map != null) + { + sendingPlayers = true; + try + { + Player[] online = PlayerInfo.Online.Items; + foreach (Player pl in online) { + pl.Game.RatedMap = false; + pl.Game.PledgeSurvive = false; + if (pl.level == oldMap) + { + if (sendAfkMain && pl.IsAfk) + PlayerActions.ChangeMap(pl, Server.mainLevel); + else + PlayerActions.ChangeMap(pl, Map); + } + } + oldMap.Unload(true, false); + } + catch { } + sendingPlayers = false; + + StartRound(); + } + } + + public void StartVote() + { + if (maps.Count < 3) return; + + // Make sure these are cleared or bad stuff happens! + votes.Clear(); + voted.Clear(); + + byte i = 0; + string opt, str = ""; + while (i < Math.Min(voteCount, maps.Count - 1)) + { + opt = maps[rand.Next(maps.Count)]; + if (!votes.ContainsKey(opt) && opt != Map.name) + { + votes.Add(opt, 0); + str += "%S, &5" + opt.Capitalize(); + i++; + } + } + + Map.ChatLevel("Vote for the next map! The vote ends in " + voteTime + " minute" + (voteTime == 1 ? "" : "s") +"."); + Map.ChatLevel("Choices: " + str.Remove(0, 4)); + + voteTimer = new Timer(TimeSpan.FromMinutes(voteTime).TotalMilliseconds); + voteTimer.AutoReset = false; + voteTimer.Elapsed += delegate + { + try { + EndVote(); + voteTimer.Dispose(); + } + catch (Exception e) { Logger.LogError(e); } + }; + voteTimer.Start(); + voteActive = true; + } + + public void EndVote() { + if (!voteActive) return; + + voteActive = false; + Logger.Log(LogType.GameActivity, "[Lava Survival] Vote ended."); + KeyValuePair most = new KeyValuePair(String.Empty, -1); + foreach (KeyValuePair kvp in votes) + { + if (kvp.Value > most.Value) most = kvp; + Map.ChatLevelOps("&5" + kvp.Key.Capitalize() + "&f: &a" + kvp.Value); + } + votes.Clear(); + voted.Clear(); + + Map.ChatLevel("The vote has ended! &5" + most.Key.Capitalize() + " %Swon with &a" + most.Value + " %Svote" + (most.Value == 1 ? "" : "s") + "."); + Map.ChatLevel("You will be transferred in 5 seconds..."); + transferTimer = new Timer(5000); + transferTimer.AutoReset = false; + transferTimer.Elapsed += delegate + { + try + { + LoadMap(most.Key); + transferTimer.Dispose(); + } + catch (Exception e) { Logger.LogError(e); } + }; + transferTimer.Start(); + } + + public bool AddVote(Player p, string vote) { + if (!voteActive || voted.Contains(p.name) || !votes.ContainsKey(vote)) return false; + int temp = votes[vote] + 1; + votes.Remove(vote); + votes.Add(vote, temp); + voted.Add(p.name); + return true; + } + + public bool HasVote(string vote) { + return voteActive && votes.ContainsKey(vote); + } + + void KillPlayer(Player p) { + if (lifeNum < 1) return; + string name = p.name.ToLower(); + if (!deaths.ContainsKey(name)) deaths.Add(name, 0); + deaths[name]++; + if (!IsPlayerDead(p)) return; + + Player[] online = PlayerInfo.Online.Items; + foreach (Player pl in online) { + if (pl != p && pl.level == Map) { + Player.Message(pl, p.ColoredName + " &4ran out of lives, and is out of the round!"); + } + } + + Player.Message(p, "&4You ran out of lives, and are out of the round!"); + Player.Message(p, "&4You can still watch, but you cannot build."); + } + } +} diff --git a/MCGalaxy/Games/LavaSurvival/LSGame.cs b/MCGalaxy/Games/LavaSurvival/LSGame.cs new file mode 100644 index 000000000..cf10e0657 --- /dev/null +++ b/MCGalaxy/Games/LavaSurvival/LSGame.cs @@ -0,0 +1,165 @@ +/* + Copyright 2011 MCForge + + Dual-licensed under the Educational Community License, Version 2.0 and + the GNU General Public License, Version 3 (the "Licenses"); you may + not use this file except in compliance with the Licenses. You may + obtain a copy of the Licenses at + + http://www.opensource.org/licenses/ecl2.php + http://www.gnu.org/licenses/gpl-3.0.html + + Unless required by applicable law or agreed to in writing, + software distributed under the Licenses are distributed on an "AS IS" + BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + or implied. See the Licenses for the specific language governing + permissions and limitations under the Licenses. +*/ +using System; +using System.Collections.Generic; +using System.Text; +using System.Timers; +using MCGalaxy.Commands.World; +using MCGalaxy.Maths; + +namespace MCGalaxy.Games { + public sealed partial class LSGame : RoundsGame { + // Private variables + const string propsDir = "properties/lavasurvival/"; + List maps, voted; + Dictionary votes, deaths; + Random rand = new Random(); + Timer announceTimer, voteTimer, transferTimer; + DateTime startTime; + + // Public variables + public bool running = false, roundActive = false, flooded = false, voteActive = false, sendingPlayers = false; + public MapSettings mapSettings; + public MapData mapData; + + public override string GameName { get { return "Lava survival"; } } + public override bool Running { get { return running; } } + + // Settings + public bool startOnStartup, sendAfkMain = true; + public byte voteCount = 2; + public int lifeNum = 3; + public double voteTime = 2; + + // Constructors + public LSGame() { + maps = new List(); + voted = new List(); + votes = new Dictionary(); + deaths = new Dictionary(); + announceTimer = new Timer(60000); + announceTimer.AutoReset = true; + announceTimer.Elapsed += delegate + { + if (!flooded) AnnounceTimeLeft(true, false); + }; + LoadSettings(); + } + + // Public methods + public byte Start(string mapName = "") + { + if (running) return 1; // Already started + if (maps.Count < 3) return 2; // Not enough maps + if (!String.IsNullOrEmpty(mapName) && !HasMap(mapName)) return 3; // Map doesn't exist + + deaths.Clear(); + running = true; + Logger.Log(LogType.GameActivity, "[Lava Survival] Game started."); + + try { + LoadMap(String.IsNullOrEmpty(mapName) ? maps[rand.Next(maps.Count)] : mapName); + HookEventHandlers(); + } catch (Exception e) { + Logger.LogError(e); running = false; return 4; + } + return 0; + } + + public override void End() { + if (!running) return; + UnhookEventHandlers(); + + running = false; + roundActive = false; + voteActive = false; + flooded = false; + deaths.Clear(); + if (announceTimer.Enabled) announceTimer.Stop(); + try { mapData.Dispose(); } + catch { } + try { voteTimer.Dispose(); } + catch { } + try { transferTimer.Dispose(); } + catch { } + Map.Unload(true, false); + Map = null; + Logger.Log(LogType.GameActivity, "[Lava Survival] Game stopped."); + } + + public bool IsPlayerDead(Player p) { + string name = p.name.ToLower(); + if (lifeNum < 1 || !deaths.ContainsKey(name)) + return false; + return (deaths[name] >= lifeNum); + } + + public void AddMap(string name) { + if (!String.IsNullOrEmpty(name) && !HasMap(name)) { + maps.Add(name.ToLower()); + SaveSettings(); + } + } + + public void RemoveMap(string name) { + if (maps.CaselessRemove(name)) { + SaveSettings(); + } + } + + public bool HasMap(string name) { + return maps.CaselessContains(name); + } + + public bool InSafeZone(ushort x, ushort y, ushort z) { + if (mapSettings == null) return false; + return x >= mapSettings.safeZone[0].X && x <= mapSettings.safeZone[1].X && y >= mapSettings.safeZone[0].Y + && y <= mapSettings.safeZone[1].Y && z >= mapSettings.safeZone[0].Z && z <= mapSettings.safeZone[1].Z; + } + + public List Maps { get { return new List(maps); } } + + + public override bool HandlesChatMessage(Player p, string message) { + if (!running || p.level != Map) return false; + message = message.ToLower(); + if (!HasVote(message)) return false; + + if (AddVote(p, message)) { + Player.Message(p, "Your vote for &5" + message.Capitalize() + " %Shas been placed. Thanks!"); + Map.ChatLevelOps(p.name + " voted for &5" + message.Capitalize() + "%S."); + return true; + } else { + Player.Message(p, "&cYou already voted!"); + return true; + } + } + + public override void PlayerJoinedLevel(Player p, Level lvl, Level oldLevl) { + if (running && !sendingPlayers && Map == lvl) { + if (roundActive) { + AnnounceRoundInfo(p); + AnnounceTimeLeft(!flooded, true, p); + } else { + Player.Message(p, "Vote for the next map!"); + Player.Message(p, "Choices: &5" + votes.Keys.Join("%S, &5")); + } + } + } + } +} diff --git a/MCGalaxy/Games/LavaSurvival/LavaSurvival.Game.cs b/MCGalaxy/Games/LavaSurvival/LavaSurvival.Game.cs deleted file mode 100644 index 2b6c057b2..000000000 --- a/MCGalaxy/Games/LavaSurvival/LavaSurvival.Game.cs +++ /dev/null @@ -1,56 +0,0 @@ -/* - Copyright 2011 MCForge - - Dual-licensed under the Educational Community License, Version 2.0 and - the GNU General Public License, Version 3 (the "Licenses"); you may - not use this file except in compliance with the Licenses. You may - obtain a copy of the Licenses at - - http://www.opensource.org/licenses/ecl2.php - http://www.gnu.org/licenses/gpl-3.0.html - - Unless required by applicable law or agreed to in writing, - software distributed under the Licenses are distributed on an "AS IS" - BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - or implied. See the Licenses for the specific language governing - permissions and limitations under the Licenses. -*/ -using System; - -namespace MCGalaxy.Games { - - public sealed partial class LavaSurvival : IGame { - - public override bool HandlesChatMessage(Player p, string message) { - if (!HasPlayer(p)) return false; - message = message.ToLower(); - if (!HasVote(message)) return false; - - if (AddVote(p, message)) { - Player.Message(p, "Your vote for &5" + message.Capitalize() + " %Shas been placed. Thanks!"); - return true; - } else { - Player.Message(p, "&cYou already voted!"); - return true; - } - } - - - public override void PlayerJoinedServer(Player p) { - if (!active) return; - Player.Message(p, "There is a &aLava Survival %Sgame active! Join it by typing /ls go"); - } - - public override void PlayerJoinedLevel(Player p, Level lvl, Level oldLevl) { - if (active && !sendingPlayers && map == lvl) { - if (roundActive) { - AnnounceRoundInfo(p); - AnnounceTimeLeft(!flooded, true, p); - } else { - Player.Message(p, "Vote for the next map!"); - Player.Message(p, "Choices: &5" + votes.Keys.Join("%S, &5")); - } - } - } - } -} diff --git a/MCGalaxy/Games/LevelPicker.cs b/MCGalaxy/Games/LevelPicker.cs index ab7a9d965..035d8048c 100644 --- a/MCGalaxy/Games/LevelPicker.cs +++ b/MCGalaxy/Games/LevelPicker.cs @@ -24,7 +24,9 @@ namespace MCGalaxy.Games { public abstract class LevelPicker { public string QueuedMap; public List RecentMaps = new List(); - + public int VoteTime = 20; + public bool Voting; + internal string Candidate1 = "", Candidate2 = "", Candidate3 = ""; internal int Votes1 = 0, Votes2 = 0, Votes3 = 0; @@ -43,16 +45,16 @@ namespace MCGalaxy.Games { if (QueuedMap != null) return QueuedMap; try { - List maps = GetCandidateLevels(); + List maps = GetCandidateMaps(); if (maps == null) return null; RemoveRecentLevels(maps); Votes1 = 0; Votes2 = 0; Votes3 = 0; Random r = new Random(); - Candidate1 = GetRandomLevel(r, maps); - Candidate2 = GetRandomLevel(r, maps); - Candidate3 = GetRandomLevel(r, maps); + Candidate1 = GetRandomMap(r, maps); + Candidate2 = GetRandomMap(r, maps); + Candidate3 = GetRandomMap(r, maps); if (!game.Running) return null; DoLevelVote(game); @@ -80,7 +82,7 @@ namespace MCGalaxy.Games { } void DoLevelVote(IGame game) { - Server.votingforlevel = true; + Voting = true; Player[] players = PlayerInfo.Online.Items; foreach (Player pl in players) { if (pl.level != game.Map) continue; @@ -88,7 +90,7 @@ namespace MCGalaxy.Games { } VoteCountdown(game); - Server.votingforlevel = false; + Voting = false; } void VoteCountdown(IGame game) { @@ -96,16 +98,17 @@ namespace MCGalaxy.Games { Player[] players = PlayerInfo.Online.Items; foreach (Player pl in players) { if (pl.level != game.Map || pl.Supports(CpeExt.MessageTypes)) continue; - pl.SendMessage("You have 20 seconds to vote for the next map"); + pl.SendMessage("You have " + VoteTime + " seconds to vote for the next map"); } - for (int i = 0; i < 20; i++) { + for (int i = 0; i < VoteTime; i++) { players = PlayerInfo.Online.Items; if (!game.Running) return; foreach (Player pl in players) { if (pl.level != game.Map || !pl.Supports(CpeExt.MessageTypes)) continue; - pl.SendCpeMessage(CpeMessageType.BottomRight1, "&e" + (20 - i) + "s %Sleft to vote"); + string timeLeft = "&e" + (VoteTime - i) + "s %Sleft to vote"; + pl.SendCpeMessage(CpeMessageType.BottomRight1, timeLeft); } Thread.Sleep(1000); } @@ -115,33 +118,25 @@ namespace MCGalaxy.Games { Player[] online = PlayerInfo.Online.Items; foreach (Player pl in online) pl.voted = false; - if (Votes1 >= Votes2) { - if (Votes3 > Votes1 && Votes3 > Votes2) { - return Candidate3; - } else { - return Candidate1; - } + if (Votes3 > Votes1 && Votes3 > Votes2) { + return Candidate3; + } else if (Votes1 >= Votes2) { + return Candidate1; } else { - if (Votes3 > Votes1 && Votes3 > Votes2) { - return Candidate3; - } else { - return Candidate2; - } + return Candidate2; } - } - internal static string GetRandomLevel(Random r, List maps) { + internal static string GetRandomMap(Random r, List maps) { int i = r.Next(0, maps.Count); - string map = maps[i]; - + string map = maps[i]; maps.RemoveAt(i); return map; } /// Returns a list of maps that can be used for a round of this game. /// null if not enough levels are available, otherwise the list of levels. - public abstract List GetCandidateLevels(); + public abstract List GetCandidateMaps(); /// Sends the formatted vote message to the player (using bottom right if supported) public void SendVoteMessage(Player p) { @@ -156,5 +151,15 @@ namespace MCGalaxy.Games { Player.Message(p, line2); } } + + public bool HandlesMessage(Player p, string message) { + if (!Voting) return false; + message = message.ToLower(); + + return + Player.CheckVote(message, p, "1", "one", ref Votes1) || + Player.CheckVote(message, p, "2", "two", ref Votes2) || + Player.CheckVote(message, p, "3", "three", ref Votes3); + } } } diff --git a/MCGalaxy/Games/ZombieSurvival/HUD.cs b/MCGalaxy/Games/ZombieSurvival/HUD.cs index 0e02c54d9..da1f404c9 100644 --- a/MCGalaxy/Games/ZombieSurvival/HUD.cs +++ b/MCGalaxy/Games/ZombieSurvival/HUD.cs @@ -23,7 +23,7 @@ namespace MCGalaxy.Games.ZS { internal static void UpdateAllPrimary(ZSGame game) { int left = (int)(game.RoundEnd - DateTime.UtcNow).TotalSeconds; string status = FormatPrimary(game, left); - MessageAll(game, CpeMessageType.Status1, status); + game.MessageMap(CpeMessageType.Status1, status); } internal static void UpdatePrimary(ZSGame game, Player p) { @@ -34,7 +34,7 @@ namespace MCGalaxy.Games.ZS { internal static void UpdateAllSecondary(ZSGame game) { string status = FormatSecondary(game); - MessageAll(game, CpeMessageType.Status2, status); + game.MessageMap(CpeMessageType.Status2, status); } internal static void UpdateSecondary(ZSGame game, Player p) { @@ -70,10 +70,10 @@ namespace MCGalaxy.Games.ZS { string timespan = GetTimeLeft(seconds); if (timespan.Length > 0) { const string format = "&a{0} %Salive %S({2}, map: {1})"; - return String.Format(format, game.Alive.Count, game.MapName, timespan); + return String.Format(format, game.Alive.Count, game.Map.MapName, timespan); } else { const string format = "&a{0} %Salive %S(map: {1})"; - return String.Format(format, game.Alive.Count, game.MapName); + return String.Format(format, game.Alive.Count, game.Map.MapName); } } @@ -88,14 +88,5 @@ namespace MCGalaxy.Games.ZS { string state = ", you are " + (p.Game.Infected ? "&cdead" : "&aalive"); return money + state; } - - static void MessageAll(ZSGame game, CpeMessageType type, string message) { - if (!game.Running) return; - Player[] online = PlayerInfo.Online.Items; - foreach (Player p in online) { - if (!p.level.name.CaselessEq(game.MapName)) continue; - p.SendCpeMessage(type, message); - } - } } } diff --git a/MCGalaxy/Games/ZombieSurvival/LevelPicker.cs b/MCGalaxy/Games/ZombieSurvival/LevelPicker.cs deleted file mode 100644 index 141ca76a0..000000000 --- a/MCGalaxy/Games/ZombieSurvival/LevelPicker.cs +++ /dev/null @@ -1,61 +0,0 @@ -/* - Copyright 2010 MCLawl Team - - Created by Snowl (David D.) and Cazzar (Cayde D.) - - Dual-licensed under the Educational Community License, Version 2.0 and - the GNU General Public License, Version 3 (the "Licenses"); you may - not use this file except in compliance with the Licenses. You may - obtain a copy of the Licenses at - - http://www.osedu.org/licenses/ECL-2.0 - http://www.gnu.org/licenses/gpl-3.0.html - - Unless required by applicable law or agreed to in writing, - software distributed under the Licenses are distributed on an "AS IS" - BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - or implied. See the Licenses for the specific language governing - permissions and limitations under the Licenses. - */ -using System; -using System.Collections.Generic; -using System.IO; - -namespace MCGalaxy.Games.ZS { - internal class ZSLevelPicker : LevelPicker { - - public override List GetCandidateLevels() { - List maps = null; - if (ZSConfig.LevelList.Count > 0) { - maps = new List(ZSConfig.LevelList); - } else { - maps = AllMaps(); - } - - foreach (string ignore in ZSConfig.IgnoredLevelList) - maps.Remove(ignore); - - bool useLevelList = ZSConfig.LevelList.Count > 0; - if (ZSConfig.ChangeLevels && maps.Count <= 3) { - string group = useLevelList ? "in your level list " : ""; - Logger.Log(LogType.Warning, "You must have more than 3 levels {0}to change levels in Zombie Survival", group); - return null; - } else if (!ZSConfig.ChangeLevels && maps.Count == 0) { - string group = useLevelList ? "in your level list " : ""; - Logger.Log(LogType.Warning, "You must have at least 1 level {0}to play Zombie Survival", group); - return null; - } - return maps; - } - - static List AllMaps() { - string[] files = LevelInfo.AllMapFiles(); - List maps = new List(files.Length); - - foreach (string file in files) { - string map = Path.GetFileNameWithoutExtension(file); - maps.Add(map); - } - return maps; - } - } -} diff --git a/MCGalaxy/Games/ZombieSurvival/Rewards.cs b/MCGalaxy/Games/ZombieSurvival/Rewards.cs deleted file mode 100644 index 21fa2e826..000000000 --- a/MCGalaxy/Games/ZombieSurvival/Rewards.cs +++ /dev/null @@ -1,122 +0,0 @@ -/* - Copyright 2010 MCLawl Team - - Created by Snowl (David D.) and Cazzar (Cayde D.) - - Dual-licensed under the Educational Community License, Version 2.0 and - the GNU General Public License, Version 3 (the "Licenses"); you may - not use this file except in compliance with the Licenses. You may - obtain a copy of the Licenses at - - http://www.osedu.org/licenses/ECL-2.0 - http://www.gnu.org/licenses/gpl-3.0.html - - Unless required by applicable law or agreed to in writing, - software distributed under the Licenses are distributed on an "AS IS" - BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - or implied. See the Licenses for the specific language governing - permissions and limitations under the Licenses. - */ -using System; -using System.Collections.Generic; - -namespace MCGalaxy.Games.ZS { - - internal static class Rewards { - - public static void HandOut(ZSGame game) { - Player[] alive = game.Alive.Items, dead = game.Infected.Items; - game.Map.ChatLevel("&aThe game has ended!"); - - if (alive.Length == 0) game.Map.ChatLevel("&4Zombies have won this round."); - else if (alive.Length == 1) game.Map.ChatLevel("&2Congratulations to the sole survivor:"); - else game.Map.ChatLevel("&2Congratulations to the survivors:"); - AnnounceWinners(game, alive, dead); - - game.Map.Config.RoundsPlayed++; - if (alive.Length > 0) { - game.Map.Config.RoundsHumanWon++; - foreach (Player p in alive) - IncreaseAliveStats(p, game); - } - - GiveMoney(game, alive); - } - - static void AnnounceWinners(ZSGame game, Player[] alive, Player[] dead) { - if (alive.Length > 0) { - string winners = alive.Join(p => p.ColoredName); - game.Map.ChatLevel(winners); - return; - } - - int maxKills = 0, count = 0; - for (int i = 0; i < dead.Length; i++) { - maxKills = Math.Max(maxKills, dead[i].Game.CurrentInfected); - } - for (int i = 0; i < dead.Length; i++) { - if (dead[i].Game.CurrentInfected == maxKills) count++; - } - - string group = count == 1 ? " zombie " : " zombies "; - string suffix = maxKills == 1 ? " %Skill" : " %Skills"; - StringFormatter formatter = p => p.Game.CurrentInfected == maxKills ? p.ColoredName : null; - - game.Map.ChatLevel("&8Best" + group + "%S(&b" + maxKills - + suffix + "%S)&8: " + dead.Join(formatter)); - } - - static void IncreaseAliveStats(Player p, ZSGame game) { - if (p.Game.PledgeSurvive) { - Player.Message(p, "You received &a5 %3" + ServerConfig.Currency + - " %Sfor successfully pledging that you would survive."); - p.SetMoney(p.money + 5); - } - - p.Game.CurrentRoundsSurvived++; - p.Game.TotalRoundsSurvived++; - p.Game.MaxRoundsSurvived = Math.Max(p.Game.CurrentRoundsSurvived, p.Game.MaxRoundsSurvived); - p.SetPrefix(); // stars before name - } - - static void GiveMoney(ZSGame game, Player[] alive) { - Player[] online = PlayerInfo.Online.Items; - Random rand = new Random(); - - foreach (Player pl in online) { - if (!pl.level.name.CaselessEq(game.MapName)) continue; - pl.Game.ResetInvisibility(); - int reward = GetMoneyReward(pl, alive, rand); - - if (reward == -1) { - pl.SendMessage("You may not hide inside a block! No " + ServerConfig.Currency + " for you."); reward = 0; - } else if (reward > 0) { - pl.SendMessage(Colors.gold + "You gained " + reward + " " + ServerConfig.Currency); - } - - pl.SetMoney(pl.money + reward); - pl.Game.ResetZombieState(); - if (pl.Game.Referee) { - pl.SendMessage("You gained one " + ServerConfig.Currency + " because you're a ref. Would you like a medal as well?"); - pl.SetMoney(pl.money + 1); - } - - Entities.GlobalRespawn(pl, false); - TabList.Add(pl, pl, Entities.SelfID); - HUD.UpdateTertiary(pl); - } - } - - static int GetMoneyReward(Player pl, Player[] alive, Random rand) { - if (pl.CheckIfInsideBlock()) return -1; - - if (alive.Length == 0) { - return rand.Next(1 + pl.Game.CurrentInfected, 5 + pl.Game.CurrentInfected); - } else if (alive.Length == 1 && !pl.Game.Infected) { - return rand.Next(5, 10); - } else if (alive.Length > 1 && !pl.Game.Infected) { - return rand.Next(2, 6); - } - return 0; - } - } -} diff --git a/MCGalaxy/Games/ZombieSurvival/ZSConfig.cs b/MCGalaxy/Games/ZombieSurvival/ZSConfig.cs index 9d882cd2f..b3f386abf 100644 --- a/MCGalaxy/Games/ZombieSurvival/ZSConfig.cs +++ b/MCGalaxy/Games/ZombieSurvival/ZSConfig.cs @@ -61,8 +61,6 @@ namespace MCGalaxy.Games { public static int ZombieInvisibilityDuration = 5; [ConfigInt("zombie-zinvisibility-potions", "Zombie", 4, 1)] public static int ZombieInvisibilityPotions = 4; - [ConfigBool("enable-changing-levels", "Zombie", true)] - public static bool ChangeLevels = true; [ConfigString("revive-notime-msg", "Revive", "It's too late. The humans do not have enough time left to make more revive potions.")] diff --git a/MCGalaxy/Games/ZombieSurvival/ZSPlugin.cs b/MCGalaxy/Games/ZombieSurvival/ZSGame.Plugin.cs similarity index 78% rename from MCGalaxy/Games/ZombieSurvival/ZSPlugin.cs rename to MCGalaxy/Games/ZombieSurvival/ZSGame.Plugin.cs index 6c3767cf5..329319bcf 100644 --- a/MCGalaxy/Games/ZombieSurvival/ZSPlugin.cs +++ b/MCGalaxy/Games/ZombieSurvival/ZSGame.Plugin.cs @@ -21,45 +21,48 @@ using MCGalaxy.Events.EconomyEvents; using MCGalaxy.Events.EntityEvents; using MCGalaxy.Events.LevelEvents; using MCGalaxy.Events.PlayerEvents; +using MCGalaxy.Events.ServerEvents; +using MCGalaxy.Games.ZS; using MCGalaxy.Network; using BlockID = System.UInt16; -namespace MCGalaxy.Games.ZS { - public sealed class ZSPlugin : Plugin_Simple { - public override string creator { get { return Server.SoftwareName + " team"; } } - public override string MCGalaxy_Version { get { return Server.VersionString; } } - public override string name { get { return "Core_ZSPlugin"; } } - public ZSGame Game; +namespace MCGalaxy.Games { + public sealed partial class ZSGame : RoundsGame { - public override void Load(bool startup) { + void HookEventHandlers() { OnEntitySpawnedEvent.Register(HandleEntitySpawned, Priority.High); OnTabListEntryAddedEvent.Register(HandleTabListEntryAdded, Priority.High); OnMoneyChangedEvent.Register(HandleMoneyChanged, Priority.High); + OnBlockChangeEvent.Register(HandleBlockChange, Priority.High); + OnLevelUnloadEvent.Register(HandleLevelUnload, Priority.High); + OnSendingHeartbeatEvent.Register(HandleSendingHeartbeat, Priority.High); + OnPlayerConnectEvent.Register(HandlePlayerConnect, Priority.High); OnPlayerDisconnectEvent.Register(HandlePlayerDisconnect, Priority.High); OnPlayerMoveEvent.Register(HandlePlayerMove, Priority.High); OnPlayerActionEvent.Register(HandlePlayerAction, Priority.High); OnPlayerSpawningEvent.Register(HandlePlayerSpawning, Priority.High); - OnBlockChangeEvent.Register(HandleBlockChange, Priority.High); - OnLevelUnloadEvent.Register(HandleLevelUnload, Priority.High); } - public override void Unload(bool shutdown) { + void UnhookEventHandlers() { OnEntitySpawnedEvent.Unregister(HandleEntitySpawned); OnTabListEntryAddedEvent.Unregister(HandleTabListEntryAdded); OnMoneyChangedEvent.Unregister(HandleMoneyChanged); + OnBlockChangeEvent.Unregister(HandleBlockChange); + OnLevelUnloadEvent.Unregister(HandleLevelUnload); + OnSendingHeartbeatEvent.Unregister(HandleSendingHeartbeat); + OnPlayerConnectEvent.Unregister(HandlePlayerConnect); OnPlayerDisconnectEvent.Unregister(HandlePlayerDisconnect); OnPlayerMoveEvent.Unregister(HandlePlayerMove); OnPlayerActionEvent.Unregister(HandlePlayerAction); OnPlayerSpawningEvent.Unregister(HandlePlayerSpawning); - OnBlockChangeEvent.Unregister(HandleBlockChange); - OnLevelUnloadEvent.Unregister(HandleLevelUnload); } - + + void HandleTabListEntryAdded(Entity entity, ref string tabName, ref string tabGroup, Player dst) { Player p = entity as Player; - if (p == null || p.level != Game.Map) return; + if (p == null || p.level != Map) return; if (p.Game.Referee) { tabGroup = "&2Referees"; @@ -76,7 +79,7 @@ namespace MCGalaxy.Games.ZS { } void HandleMoneyChanged(Player p) { - if (p.level != Game.Map) return; + if (p.level != Map) return; HUD.UpdateTertiary(p); } @@ -93,16 +96,16 @@ namespace MCGalaxy.Games.ZS { } void HandlePlayerConnect(Player p) { - if (!ZSConfig.SetMainLevel) return; - Player.Message(p, "Zombie Survival is running! Type %T/ZS go %Sto join."); + if (ZSConfig.SetMainLevel) return; + Player.Message(p, "&3Zombie Survival %Sis running! Type %T/ZS go %Sto join"); } void HandlePlayerDisconnect(Player p, string reason) { - Game.PlayerLeftGame(p); + PlayerLeftGame(p); } void HandlePlayerMove(Player p, Position next, byte rotX, byte rotY) { - if (!Game.RoundInProgress || p.level != Game.Map) return; + if (!RoundInProgress || p.level != Map) return; bool reverted = MovementCheck.DetectNoclip(p, next) || MovementCheck.DetectSpeedhack(p, next, ZSConfig.MaxMoveDistance); @@ -111,10 +114,10 @@ namespace MCGalaxy.Games.ZS { void HandlePlayerAction(Player p, PlayerAction action, string message, bool stealth) { if (!(action == PlayerAction.Referee || action == PlayerAction.UnReferee)) return; - if (p.level != Game.Map) return; + if (p.level != Map) return; if (action == PlayerAction.UnReferee) { - Game.PlayerJoinedLevel(p, Game.Map, Game.Map); + PlayerJoinedLevel(p, Map, Map); Command.all.FindByName("Spawn").Use(p, ""); p.Game.Referee = false; @@ -137,25 +140,24 @@ namespace MCGalaxy.Games.ZS { } void HandlePlayerSpawning(Player p, ref Position pos, ref byte yaw, ref byte pitch, bool respawning) { - if (p.level != Game.Map) return; - - if (!p.Game.Referee && !p.Game.Infected && Game.RoundInProgress) { - Game.InfectPlayer(p, null); + if (p.level != Map) return; + if (!p.Game.Referee && !p.Game.Infected && RoundInProgress) { + InfectPlayer(p, null); } } void HandleBlockChange(Player p, ushort x, ushort y, ushort z, BlockID block, bool placing) { - if (p.level != Game.Map) return; - BlockID old = Game.Map.GetBlock(x, y, z); + if (p.level != Map) return; + BlockID old = Map.GetBlock(x, y, z); - if (Game.Map.Config.BuildType == BuildType.NoModify) { + if (Map.Config.BuildType == BuildType.NoModify) { p.RevertBlock(x, y, z); p.cancelBlock = true; return; } - if (Game.Map.Config.BuildType == BuildType.ModifyOnly && Game.Map.Props[old].OPBlock) { + if (Map.Config.BuildType == BuildType.ModifyOnly && Map.Props[old].OPBlock) { p.RevertBlock(x, y, z); p.cancelBlock = true; return; } - if (Pillaring.Handles(p, x, y, z, placing, block, old, Game)) { + if (Pillaring.Handles(p, x, y, z, placing, block, old, this)) { p.cancelBlock = true; return; } @@ -167,13 +169,19 @@ namespace MCGalaxy.Games.ZS { } p.Game.BlocksLeft--; - if ((p.Game.BlocksLeft % 10) == 0 || (p.Game.BlocksLeft >= 0 && p.Game.BlocksLeft <= 10)) + if ((p.Game.BlocksLeft % 10) == 0 || (p.Game.BlocksLeft >= 0 && p.Game.BlocksLeft <= 10)) { Player.Message(p, "Blocks Left: &4" + p.Game.BlocksLeft); + } } } void HandleLevelUnload(Level lvl) { - if (lvl == Game.Map) lvl.cancelunload = true; + if (lvl == Map) lvl.cancelunload = true; + } + + void HandleSendingHeartbeat(Heartbeat service, ref string name) { + if (!ZSConfig.IncludeMapInHeartbeat || Map == null) return; + name += " (map: " + Map.MapName + ")"; } } } diff --git a/MCGalaxy/Games/ZombieSurvival/ZombieGame.Core.cs b/MCGalaxy/Games/ZombieSurvival/ZSGame.Round.cs similarity index 54% rename from MCGalaxy/Games/ZombieSurvival/ZombieGame.Core.cs rename to MCGalaxy/Games/ZombieSurvival/ZSGame.Round.cs index 19c14198e..91102c9e8 100644 --- a/MCGalaxy/Games/ZombieSurvival/ZombieGame.Core.cs +++ b/MCGalaxy/Games/ZombieSurvival/ZSGame.Round.cs @@ -18,22 +18,39 @@ */ using System; using System.Collections.Generic; +using System.IO; using System.Threading; +using MCGalaxy.Commands.World; using MCGalaxy.Games.ZS; using MCGalaxy.Network; namespace MCGalaxy.Games { - public sealed partial class ZSGame : RoundsGame { - public override string GameName { get { return "Zombie survival"; } } - + public sealed partial class ZSGame : RoundsGame { + string lastKiller = ""; + int infectCombo = 0; + protected override void DoRound() { if (!Running) return; List players = DoRoundCountdown(); if (players == null) return; - Random random = new Random(); RoundInProgress = true; + StartRound(players); + if (!running) return; + + if (!running) return; + EndRound(); + Picker.AddRecentMap(Map.MapName); + + if (RoundsLeft > 0) { + string map = Picker.ChooseNextLevel(this); + if (map != null) ChangeLevel(map); + } + } + + void StartRound(List players) { + Random random = new Random(); int roundMins = random.Next(Map.Config.MinRoundTime, Map.Config.MaxRoundTime); string suffix = roundMins == 1 ? " %Sminute!" : " %Sminutes!"; Map.ChatLevel("This round will last for &a" + roundMins + suffix); @@ -46,64 +63,72 @@ namespace MCGalaxy.Games { } Infected.Clear(); - Player first = PickFirstZombie(random, players); - Map.ChatLevel("&c" + first.DisplayName + " %Sstarted the infection!"); - InfectPlayer(first, null); - - DoCoreGame(random); - if (!Running) return; - EndRound(); - Picker.AddRecentMap(MapName); - - if (RoundsLeft > 0 && ZSConfig.ChangeLevels) { - string map = Picker.ChooseNextLevel(this); - if (map != null) ChangeLevel(map); - } - } - - Player PickFirstZombie(Random random, List players) { Player first = null; do { - first = QueuedZombie != null ? - PlayerInfo.FindExact(QueuedZombie) : players[random.Next(players.Count)]; + first = QueuedZombie != null ? PlayerInfo.FindExact(QueuedZombie) : players[random.Next(players.Count)]; QueuedZombie = null; - } while (first == null || !first.level.name.CaselessEq(MapName)); - return first; + } while (first == null || first.level != Map); + + Map.ChatLevel("&c" + first.DisplayName + " %Sstarted the infection!"); + InfectPlayer(first, null); + } + + /// If there are no infected players left, randomly selected one of the alive players to continue the infection. + void AssignFirstZombie() { + if (!running || !RoundInProgress || Infected.Count > 0) return; + Random random = new Random(); + Player[] alive = Alive.Items; + if (alive.Length == 0) return; + int index = random.Next(alive.Length); + + while (alive[index].Game.Referee || alive[index].level != Map) { + if (index >= alive.Length - 1) { + index = 0; + alive = Alive.Items; + if (alive.Length == 0) return; + } else { + index++; + } + } + + Player zombie = alive[index]; + Map.ChatLevel("&c" + zombie.DisplayName + " %Scontinued the infection!"); + InfectPlayer(zombie, null); } List DoRoundCountdown() { while (true) { RoundStart = DateTime.UtcNow.AddSeconds(30); - if (!Running) return null; + if (!running) return null; + SendLevelRaw("&4Starting in &f30 &4seconds", true); - Thread.Sleep(10000); if (!Running) return null; + Thread.Sleep(10000); if (!running) return null; SendLevelRaw("&4Starting in &f20 &4seconds", true); - Thread.Sleep(10000); if (!Running) return null; + Thread.Sleep(10000); if (!running) return null; SendLevelRaw("&4Starting in &f10 &4seconds", true); - Thread.Sleep(5000); if (!Running) return null; + Thread.Sleep(5000); if (!running) return null; SendLevelRaw("&4Starting in &f5 &4seconds", true); - Thread.Sleep(1000); if (!Running) return null; + Thread.Sleep(1000); if (!running) return null; SendLevelRaw("&4Starting in &f4 &4seconds", true); - Thread.Sleep(1000); if (!Running) return null; + Thread.Sleep(1000); if (!running) return null; SendLevelRaw("&4Starting in &f3 &4seconds", true); - Thread.Sleep(1000); if (!Running) return null; + Thread.Sleep(1000); if (!running) return null; SendLevelRaw("&4Starting in &f2 &4seconds", true); - Thread.Sleep(1000); if (!Running) return null; + Thread.Sleep(1000); if (!running) return null; SendLevelRaw("&4Starting in &f1 &4second", true); - Thread.Sleep(1000); if (!Running) return null; + Thread.Sleep(1000); if (!running) return null; SendLevelRaw("", true); int nonRefPlayers = 0; List players = new List(); Player[] online = PlayerInfo.Online.Items; foreach (Player p in online) { - if (!p.Game.Referee && p.level.name.CaselessEq(MapName)) { - players.Add(p); - nonRefPlayers++; - } + if (p.Game.Referee || p.level != Map) continue; + players.Add(p); + nonRefPlayers++; } - if (!Running) return null; + if (!running) return null; if (nonRefPlayers >= 2) return players; Map.ChatLevel("&cNeed 2 or more non-ref players to start a round."); } @@ -114,7 +139,7 @@ namespace MCGalaxy.Games { string lastTimeLeft = null; int lastCountdown = -1; - while (alive.Length > 0 && Running) { + while (alive.Length > 0 && running) { Player[] infected = Infected.Items; // Do round end. int seconds = (int)(RoundEnd - DateTime.UtcNow).TotalSeconds; @@ -147,23 +172,20 @@ namespace MCGalaxy.Games { int dist = ZSConfig.HitboxPrecision; foreach (Player killer in deadList) { killer.Game.Infected = true; - UpdatePlayerColor(killer, InfectCol); aliveList = Alive.Items; foreach (Player alive in aliveList) { if (alive == killer) continue; - UpdatePlayerColor(alive, alive.color); if (!MovementCheck.InRange(alive, killer, dist)) continue; if (killer.Game.Infected && !alive.Game.Infected && !alive.Game.Referee && !killer.Game.Referee - && killer.level.name.CaselessEq(MapName) - && alive.level.name.CaselessEq(MapName)) + && killer.level == Map && alive.level == Map) { InfectPlayer(alive, killer); alive.Game.LastInfecter = killer.name; - if (lastPlayerToInfect == killer.name) { + if (lastKiller == killer.name) { infectCombo++; if (infectCombo >= 2) { killer.SendMessage("You gained " + (2 + infectCombo) + " " + ServerConfig.Currency); @@ -174,13 +196,12 @@ namespace MCGalaxy.Games { infectCombo = 0; } - lastPlayerToInfect = killer.name; + lastKiller = killer.name; killer.Game.CurrentInfected++; killer.Game.TotalInfected++; killer.Game.MaxInfected = Math.Max(killer.Game.CurrentInfected, killer.Game.MaxInfected); ShowInfectMessage(random, alive, killer); - UpdatePlayerColor(alive, InfectCol); Thread.Sleep(50); } } @@ -266,10 +287,56 @@ namespace MCGalaxy.Games { "&c" + pKiller.DisplayName + "%S", pAlive.ColoredName + "%S")); } + + bool SetMap(string map) { + Picker.QueuedMap = null; + Map = LevelInfo.FindExact(map) ?? CmdLoad.LoadLevel(null, map); + if (Map == null) return false; + + Map.SaveChanges = false; + if (ZSConfig.SetMainLevel) Server.mainLevel = Map; + return true; + } - static void UpdatePlayerColor(Player p, string color) { - if (p.Game.lastSpawnColor == color) return; - p.Game.lastSpawnColor = color; + void ChangeLevel(string next) { + Map.ChatLevel("The next map has been chosen - &c" + next.ToLower()); + Map.ChatLevel("Please wait while you are transfered."); + LastMap = Map.MapName; + + if (!SetMap(next)) { + Map.ChatLevel("&cFailed to change map to " + next); + Map.ChatLevel("Continuing ZS on this map again"); + } else { + MoveToNextMap(LastMap); + + Command.all.FindByName("Unload").Use(null, LastMap); + } + } + + void MoveToNextMap(string lastMap) { + Random rnd = new Random(); + Player[] online = PlayerInfo.Online.Items; + List players = new List(online.Length); + + foreach (Player pl in online) { + pl.Game.RatedMap = false; + pl.Game.PledgeSurvive = false; + if (pl.level != Map && pl.level.name.CaselessEq(lastMap)) { + players.Add(pl); + } + } + + while (players.Count > 0) { + int i = rnd.Next(0, players.Count); + Player pl = players[i]; + + pl.SendMessage("Going to the next map - &a" + Map.MapName); + PlayerActions.ChangeMap(pl, Map); + players.RemoveAt(i); + } + } + + internal static void RespawnPlayer(Player p) { Entities.GlobalRespawn(p, false); TabList.Add(p, p, Entities.SelfID); } @@ -282,7 +349,95 @@ namespace MCGalaxy.Games { HUD.UpdateAllPrimary(this); if (!Running) return; - Rewards.HandOut(this); + Player[] alive = Alive.Items, dead = Infected.Items; + Map.ChatLevel("&aThe game has ended!"); + + if (alive.Length == 0) Map.ChatLevel("&4Zombies have won this round."); + else if (alive.Length == 1) Map.ChatLevel("&2Congratulations to the sole survivor:"); + else Map.ChatLevel("&2Congratulations to the survivors:"); + AnnounceWinners(alive, dead); + + Map.Config.RoundsPlayed++; + if (alive.Length > 0) { + Map.Config.RoundsHumanWon++; + foreach (Player p in alive) { IncreaseAliveStats(p); } + } + + GiveMoney(alive); + Level.SaveSettings(Map); + } + + void AnnounceWinners(Player[] alive, Player[] dead) { + if (alive.Length > 0) { + Map.ChatLevel(alive.Join(p => p.ColoredName)); + return; + } + + int maxKills = 0, count = 0; + for (int i = 0; i < dead.Length; i++) { + maxKills = Math.Max(maxKills, dead[i].Game.CurrentInfected); + } + for (int i = 0; i < dead.Length; i++) { + if (dead[i].Game.CurrentInfected == maxKills) count++; + } + + string group = count == 1 ? " zombie " : " zombies "; + string suffix = maxKills == 1 ? " %Skill" : " %Skills"; + StringFormatter formatter = p => p.Game.CurrentInfected == maxKills ? p.ColoredName : null; + Map.ChatLevel("&8Best" + group + "%S(&b" + maxKills + suffix + "%S)&8: " + dead.Join(formatter)); + } + + void IncreaseAliveStats(Player p) { + if (p.Game.PledgeSurvive) { + Player.Message(p, "You received &a5 %3" + ServerConfig.Currency + + " %Sfor successfully pledging that you would survive."); + p.SetMoney(p.money + 5); + } + + p.Game.CurrentRoundsSurvived++; + p.Game.TotalRoundsSurvived++; + p.Game.MaxRoundsSurvived = Math.Max(p.Game.CurrentRoundsSurvived, p.Game.MaxRoundsSurvived); + p.SetPrefix(); // stars before name + } + + void GiveMoney(Player[] alive) { + Player[] online = PlayerInfo.Online.Items; + Random rand = new Random(); + + foreach (Player pl in online) { + if (pl.level != Map) continue; + pl.Game.ResetInvisibility(); + int reward = GetMoneyReward(pl, alive, rand); + + if (reward == -1) { + pl.SendMessage("You may not hide inside a block! No " + ServerConfig.Currency + " for you."); reward = 0; + } else if (reward > 0) { + pl.SendMessage(Colors.gold + "You gained " + reward + " " + ServerConfig.Currency); + } + + pl.SetMoney(pl.money + reward); + pl.Game.ResetZombieState(); + if (pl.Game.Referee) { + pl.SendMessage("You gained one " + ServerConfig.Currency + " because you're a ref. Would you like a medal as well?"); + pl.SetMoney(pl.money + 1); + } + + ZSGame.RespawnPlayer(pl); + HUD.UpdateTertiary(pl); + } + } + + static int GetMoneyReward(Player pl, Player[] alive, Random rand) { + if (pl.CheckIfInsideBlock()) return -1; + + if (alive.Length == 0) { + return rand.Next(1 + pl.Game.CurrentInfected, 5 + pl.Game.CurrentInfected); + } else if (alive.Length == 1 && !pl.Game.Infected) { + return rand.Next(5, 10); + } else if (alive.Length > 1 && !pl.Game.Infected) { + return rand.Next(2, 6); + } + return 0; } } } diff --git a/MCGalaxy/Games/ZombieSurvival/ZombieGame.cs b/MCGalaxy/Games/ZombieSurvival/ZSGame.cs similarity index 65% rename from MCGalaxy/Games/ZombieSurvival/ZombieGame.cs rename to MCGalaxy/Games/ZombieSurvival/ZSGame.cs index 51fd1122c..fb0640103 100644 --- a/MCGalaxy/Games/ZombieSurvival/ZombieGame.cs +++ b/MCGalaxy/Games/ZombieSurvival/ZSGame.cs @@ -41,31 +41,30 @@ namespace MCGalaxy.Games { public int TotalRounds, MaxRounds, TotalInfected, MaxInfected; } - public sealed partial class ZSGame { - - public const string InfectCol = "&infect"; + public sealed partial class ZSGame : RoundsGame { + public override string GameName { get { return "Zombie survival"; } } + public override bool TeleportAllowed { get { return !RoundInProgress; } } + public override bool Running { get { return running; } } + public LevelPicker Picker = new ZSLevelPicker(); public DateTime RoundStart, RoundEnd; - public string LastLevelName = ""; + public string LastMap = ""; public VolatileArray Alive = new VolatileArray(); public VolatileArray Infected = new VolatileArray(); public string QueuedZombie; public VolatileArray Bounties = new VolatileArray(); - List infectMessages = new List(); - string lastPlayerToInfect = ""; - int infectCombo = 0; + List infectMessages = new List(); bool running; - ZSPlugin plugin = new ZSPlugin(); public void Start(Level level, int rounds) { running = true; - RoundInProgress = false; + RoundInProgress = false; if (!SetStartLevel(level)) { running = false; return; } RoundsLeft = rounds; HookStats(); - if (plugin.Game == null) { plugin.Game = this; plugin.Load(false); } + HookEventHandlers(); Thread t = new Thread(RunGame); t.Name = "MCG_ZombieGame"; @@ -73,55 +72,25 @@ namespace MCGalaxy.Games { } bool SetStartLevel(Level level) { + string mapName; if (level == null) { - List levels = Picker.GetCandidateLevels(); - if (levels == null) return false; - - MapName = LevelPicker.GetRandomLevel(new Random(), levels); - Map = LevelInfo.FindExact(MapName) - ?? CmdLoad.LoadLevel(null, MapName); - if (Map == null) return false; + List maps = Picker.GetCandidateMaps(); + if (maps == null) return false; + mapName = LevelPicker.GetRandomMap(new Random(), maps); } else { - MapName = level.name; - Map = level; - } + mapName = level.name; + } + if (!SetMap(mapName)) return false; - Map.SaveChanges = false; - Chat.MessageGlobal("A game of zombie survival is starting on: {0}", MapName); + Chat.MessageGlobal("A game of zombie survival is starting on: {0}", Map.ColoredName); Player[] players = PlayerInfo.Online.Items; foreach (Player p in players) { if (p.level != Map) continue; PlayerJoinedLevel(p, p.level, p.level); } - - if (ZSConfig.SetMainLevel) - Server.mainLevel = Map; return true; } - /// If there are no infected players left, randomly selected one of the alive players to continue the infection. - public void AssignFirstZombie() { - if (!Running || !RoundInProgress || Infected.Count > 0) return; - Random random = new Random(); - Player[] alive = Alive.Items; - if (alive.Length == 0) return; - int index = random.Next(alive.Length); - - while (alive[index].Game.Referee || !alive[index].level.name.CaselessEq(MapName)) { - if (index >= alive.Length - 1) { - index = 0; - alive = Alive.Items; - if (alive.Length == 0) return; - } else { - index++; - } - } - - Player zombie = alive[index]; - Map.ChatLevel("&c" + zombie.DisplayName + " %Scontinued the infection!"); - InfectPlayer(zombie, null); - } - public void InfectPlayer(Player p, Player killer) { if (!RoundInProgress || p == null) return; Infected.Add(p); @@ -130,7 +99,9 @@ namespace MCGalaxy.Games { p.Game.CurrentRoundsSurvived = 0; p.Game.TimeInfected = DateTime.UtcNow; p.SetPrefix(); + ResetPlayerState(p, true); + RespawnPlayer(p); CheckHumanPledge(p, killer); CheckBounty(p, killer); @@ -140,16 +111,16 @@ namespace MCGalaxy.Games { if (!RoundInProgress || p == null) return; Infected.Remove(p); Alive.Add(p); + ResetPlayerState(p, false); + RespawnPlayer(p); } void ResetPlayerState(Player p, bool infected) { p.Game.Infected = infected; p.Game.BlocksLeft = infected ? 25 : 50; - string col = infected ? Colors.red : p.color; ResetInvisibility(p); - UpdatePlayerColor(p, col); HUD.UpdateAllPrimary(this); HUD.UpdateTertiary(p); } @@ -161,61 +132,15 @@ namespace MCGalaxy.Games { Entities.GlobalSpawn(p, false); } - void ChangeLevel(string next) { - Player[] online = PlayerInfo.Online.Items; - if (Map != null) { - Level.SaveSettings(Map); - Map.ChatLevel("The next map has been chosen - " + Colors.red + next.ToLower()); - Map.ChatLevel("Please wait while you are transfered."); - } - string lastLevel = MapName; - - MapName = next; - Picker.QueuedMap = null; - CmdLoad.LoadLevel(null, next); - Map = LevelInfo.FindExact(next); - Map.SaveChanges = false; - if (ZSConfig.SetMainLevel) - Server.mainLevel = Map; - - online = PlayerInfo.Online.Items; - List players = new List(online.Length); - foreach (Player pl in online) { - pl.Game.RatedMap = false; - pl.Game.PledgeSurvive = false; - if (!pl.level.name.CaselessEq(next) && pl.level.name.CaselessEq(lastLevel)) { - players.Add(pl); - } - } - JoinInRandomOrder(players, next); - - if (LastLevelName.Length > 0) { - Command.all.FindByName("Unload").Use(null, LastLevelName); - } - LastLevelName = next; - } - - static void JoinInRandomOrder(List players, string next) { - Random rnd = new Random(); - while (players.Count > 0) { - int index = rnd.Next(0, players.Count); - Player pl = players[index]; - - pl.SendMessage("Going to the next map - &a" + next); - PlayerActions.ChangeMap(pl, next); - players.RemoveAt(index); - } - } - public override void End() { running = false; RoundsLeft = 0; RoundInProgress = false; RoundStart = DateTime.MinValue; RoundEnd = DateTime.MinValue; - if (plugin.Game != null) { plugin.Game = null; plugin.Unload(false); } + UnhookEventHandlers(); - Player[] online = PlayerInfo.Online.Items; + Player[] online = PlayerInfo.Online.Items; Alive.Clear(); Infected.Clear(); @@ -229,12 +154,11 @@ namespace MCGalaxy.Games { ResetInvisibility(pl); pl.SetPrefix(); - if (pl.level == null || !pl.level.name.CaselessEq(MapName)) continue; + if (pl.level == null || pl.level != Map) continue; HUD.Reset(pl); } - LastLevelName = ""; - MapName = ""; + LastMap = ""; Map = null; UnhookStats(); } @@ -246,6 +170,111 @@ namespace MCGalaxy.Games { } return null; } + + public override void PlayerLeftGame(Player p) { + Alive.Remove(p); + Infected.Remove(p); + p.Game.Infected = false; + RemoveBounties(p); + + AssignFirstZombie(); + HUD.UpdateAllPrimary(this); + } + + public override bool HandlesChatMessage(Player p, string message) { + if (!Running || (p.level == null || p.level != Map)) return false; + if (Picker.Voting && Picker.HandlesMessage(p, message)) return true; + + if (message[0] == '~' && message.Length > 1) { + Player[] players = PlayerInfo.Online.Items; + string type = p.Game.Infected ? " &cto zombies%S: " : " &ato humans%S: "; + string toSend = p.ColoredName + type + message.Substring(1); + + foreach (Player pl in players) { + if (pl.level != Map || !Chat.NotIgnoring(pl, p)) continue; + if (pl.Game.Referee || pl.Game.Infected == p.Game.Infected) { + pl.SendMessage(toSend); + } + } + return true; + } else if (message[0] == '`' && message.Length > 1) { + if (p.Game.Team == null) { + Player.Message(p, "You are not on a team, so cannot send a team message."); return true; + } + p.Game.Team.Chat(p, message.Substring(1)); + return true; + } + return false; + } + + void RemoveBounties(Player p) { + BountyData[] bounties = Bounties.Items; + foreach (BountyData b in bounties) { + if (!(b.Origin.CaselessEq(p.name) || b.Target.CaselessEq(p.name))) continue; + + string target = PlayerInfo.GetColoredName(p, b.Target); + Map.ChatLevel("Bounty on " + target + " %Sis no longer active."); + Bounties.Remove(b); + + Player setter = PlayerInfo.FindExact(b.Origin); + if (setter != null) setter.SetMoney(setter.money + b.Amount); + } + } + + public override void PlayerJoinedLevel(Player p, Level lvl, Level oldLvl) { + p.SendCpeMessage(CpeMessageType.BottomRight3, ""); + p.SendCpeMessage(CpeMessageType.BottomRight2, ""); + p.SendCpeMessage(CpeMessageType.BottomRight1, ""); + + if (RoundInProgress && lvl == Map && Running && p != null) { + Player.Message(p, "You joined in the middle of a round. &cYou are now infected!"); + p.Game.BlocksLeft = 25; + InfectPlayer(p, null); + } + if (RoundInProgress && oldLvl == Map && lvl != Map) { + PlayerLeftGame(p); + } + + if (lvl == Map) { + double startLeft = (RoundStart - DateTime.UtcNow).TotalSeconds; + if (startLeft >= 0) + Player.Message(p, "%a" + (int)startLeft + " %Sseconds left until the round starts. %aRun!"); + Player.Message(p, "This map has &a" + Map.Config.Likes + + " likes %Sand &c" + Map.Config.Dislikes + " dislikes"); + Player.Message(p, "This map's win chance is &a" + Map.WinChance + "%S%"); + + if (Map.Config.Authors.Length > 0) { + string[] authors = Map.Config.Authors.Replace(" ", "").Split(','); + Player.Message(p, "It was created by {0}", + authors.Join(n => PlayerInfo.GetColoredName(p, n))); + } + + HUD.UpdatePrimary(this, p); + HUD.UpdateSecondary(this, p); + HUD.UpdateTertiary(p); + + if (Picker.Voting) Picker.SendVoteMessage(p); + return; + } + + p.SetPrefix(); + HUD.Reset(p); + Alive.Remove(p); + Infected.Remove(p); + + if (oldLvl != null && oldLvl == Map) { + HUD.UpdateAllPrimary(this); + } + } + + public override void AdjustPrefix(Player p, ref string prefix) { + int winStreak = p.Game.CurrentRoundsSurvived; + + if (winStreak == 1) prefix += "&4*" + p.color; + else if (winStreak == 2) prefix += "&7*" + p.color; + else if (winStreak == 3) prefix += "&6*" + p.color; + else if (winStreak > 0) prefix += "&6" + winStreak + p.color; + } static string[] defMessages = new string[] { "{0} WIKIWOO'D {1}", "{0} stuck their teeth into {1}", "{0} licked {1}'s brain ", "{0} danubed {1}", "{0} made {1} meet their maker", "{0} tripped {1}", @@ -389,5 +418,31 @@ namespace MCGalaxy.Games { Player.Message(p, " Infected &a{0} %Splayers (max &e{1}%S)", infected, infectedMax); } #endregion + } + + internal class ZSLevelPicker : LevelPicker { + + public override List GetCandidateMaps() { + List maps = null; + bool useLevelList = ZSConfig.LevelList.Count > 0; + + if (useLevelList) { + maps = new List(ZSConfig.LevelList); + } else { + string[] files = LevelInfo.AllMapFiles(); + for (int i = 0; i < files.Length; i++) { + files[i] = Path.GetFileNameWithoutExtension(files[i]); + } + maps = new List(files); + } + + foreach (string ignore in ZSConfig.IgnoredLevelList) { maps.Remove(ignore); } + if (maps.Count < 3) { + string group = useLevelList ? "in your level list " : ""; + Logger.Log(LogType.Warning, "You must have more than 3 levels {0}to change levels in Zombie Survival", group); + return null; + } + return maps; + } } } diff --git a/MCGalaxy/Games/ZombieSurvival/ZombieGame.Game.cs b/MCGalaxy/Games/ZombieSurvival/ZombieGame.Game.cs deleted file mode 100644 index e77029174..000000000 --- a/MCGalaxy/Games/ZombieSurvival/ZombieGame.Game.cs +++ /dev/null @@ -1,148 +0,0 @@ -/* - Copyright 2010 MCLawl Team - - Created by Snowl (David D.) and Cazzar (Cayde D.) - - Dual-licensed under the Educational Community License, Version 2.0 and - the GNU General Public License, Version 3 (the "Licenses"); you may - not use this file except in compliance with the Licenses. You may - obtain a copy of the Licenses at - - http://www.osedu.org/licenses/ECL-2.0 - http://www.gnu.org/licenses/gpl-3.0.html - - Unless required by applicable law or agreed to in writing, - software distributed under the Licenses are distributed on an "AS IS" - BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - or implied. See the Licenses for the specific language governing - permissions and limitations under the Licenses. - */ -using System; -using MCGalaxy.Games.ZS; - -namespace MCGalaxy.Games { - - public sealed partial class ZSGame { - - public LevelPicker Picker = new ZSLevelPicker(); - public override bool TeleportAllowed { get { return !RoundInProgress; } } - public override bool Running { get { return running; } } - - public override void PlayerLeftGame(Player p) { - Alive.Remove(p); - Infected.Remove(p); - p.Game.Infected = false; - RemoveBounties(p); - - AssignFirstZombie(); - HUD.UpdateAllPrimary(this); - } - - public override bool HandlesChatMessage(Player p, string message) { - if (!Running || (p.level == null || !p.level.name.CaselessEq(MapName))) return false; - if (Server.votingforlevel && HandleVote(p, message)) return true; - - if (message[0] == '~' && message.Length > 1) { - Player[] players = PlayerInfo.Online.Items; - string type = p.Game.Infected ? " &cto zombies%S: " : " &ato humans%S: "; - string toSend = p.ColoredName + type + message.Substring(1); - - foreach (Player pl in players) { - if (!pl.level.name.CaselessEq(MapName) || !Chat.NotIgnoring(pl, p)) continue; - if (pl.Game.Referee || pl.Game.Infected == p.Game.Infected) { - pl.SendMessage(toSend); - } - } - return true; - } else if (message[0] == '`' && message.Length > 1) { - if (p.Game.Team == null) { - Player.Message(p, "You are not on a team, so cannot send a team message."); return true; - } - p.Game.Team.Chat(p, message.Substring(1)); - return true; - } - return false; - } - - bool HandleVote(Player p, string message) { - message = message.ToLower(); - if (Player.CheckVote(message, p, "1", "one", ref Picker.Votes1) || - Player.CheckVote(message, p, "2", "two", ref Picker.Votes2) || - Player.CheckVote(message, p, "3", "three", ref Picker.Votes3)) - return true; - return false; - } - - internal void RemoveBounties(Player p) { - BountyData[] bounties = Bounties.Items; - foreach (BountyData b in bounties) { - if (!(b.Origin.CaselessEq(p.name) || b.Target.CaselessEq(p.name))) continue; - - string target = PlayerInfo.GetColoredName(p, b.Target); - Map.ChatLevel("Bounty on " + target + " %Sis no longer active."); - Bounties.Remove(b); - - Player setter = PlayerInfo.FindExact(b.Origin); - if (setter != null) setter.SetMoney(setter.money + b.Amount); - } - } - - public override void PlayerJoinedLevel(Player p, Level lvl, Level oldLvl) { - p.SendCpeMessage(CpeMessageType.BottomRight3, ""); - p.SendCpeMessage(CpeMessageType.BottomRight2, ""); - p.SendCpeMessage(CpeMessageType.BottomRight1, ""); - if (RoundInProgress && lvl.name.CaselessEq(MapName)) { - if (Running && p != null) { - Player.Message(p, "You joined in the middle of a round. &cYou are now infected!"); - p.Game.BlocksLeft = 25; - InfectPlayer(p, null); - } - } - if (RoundInProgress && oldLvl == Map && lvl != Map) { - PlayerLeftGame(p); - } - - if (lvl.name.CaselessEq(MapName)) { - double startLeft = (RoundStart - DateTime.UtcNow).TotalSeconds; - if (startLeft >= 0) - Player.Message(p, "%a" + (int)startLeft + " %Sseconds left until the round starts. %aRun!"); - Player.Message(p, "This map has &a" + Map.Config.Likes + - " likes %Sand &c" + Map.Config.Dislikes + " dislikes"); - Player.Message(p, "This map's win chance is &a" + Map.WinChance + "%S%"); - - if (Map.Config.Authors.Length > 0) { - string[] authors = Map.Config.Authors.Replace(" ", "").Split(','); - Player.Message(p, "It was created by {0}", - authors.Join(n => PlayerInfo.GetColoredName(p, n))); - } - - HUD.UpdatePrimary(this, p); - HUD.UpdateSecondary(this, p); - HUD.UpdateTertiary(p); - - if (Server.votingforlevel) Picker.SendVoteMessage(p); - return; - } - - p.SetPrefix(); - HUD.Reset(p); - Alive.Remove(p); - Infected.Remove(p); - if (oldLvl != null && oldLvl.name.CaselessEq(MapName)) - HUD.UpdateAllPrimary(this); - } - - public override void OnHeartbeat(ref string name) { - if (!Running || !ZSConfig.IncludeMapInHeartbeat || MapName == null) return; - name += " (map: " + MapName + ")"; - } - - public override void AdjustPrefix(Player p, ref string prefix) { - int winStreak = p.Game.CurrentRoundsSurvived; - - if (winStreak == 1) prefix += "&4*" + p.color; - else if (winStreak == 2) prefix += "&7*" + p.color; - else if (winStreak == 3) prefix += "&6*" + p.color; - else if (winStreak > 0) prefix += "&6" + winStreak + p.color; - } - } -} diff --git a/MCGalaxy/Levels/Level.cs b/MCGalaxy/Levels/Level.cs index 883f46ab7..c6f5be7b1 100644 --- a/MCGalaxy/Levels/Level.cs +++ b/MCGalaxy/Levels/Level.cs @@ -117,10 +117,10 @@ namespace MCGalaxy { public bool ShouldShowJoinMessage(Level prev) { ZSGame zs = Server.zombie; - if (zs.Running && name.CaselessEq(zs.MapName) && - (prev == this || zs.LastLevelName.Length == 0 || prev.name.CaselessEq(zs.LastLevelName))) + if (zs.Running && this == zs.Map && + (prev == this || zs.LastMap.Length == 0 || prev.name.CaselessEq(zs.LastMap))) return false; - if (Server.lava.active && Server.lava.HasMap(name)) + if (Server.lava.Running && Server.lava.HasMap(name)) return false; return true; } @@ -128,10 +128,8 @@ namespace MCGalaxy { /// The currently active game running on this map, /// or null if there is no game running. public IGame CurrentGame() { - if (Server.zombie.Running && name.CaselessEq(Server.zombie.MapName)) - return Server.zombie; - if (Server.lava.active && Server.lava.map == this) - return Server.lava; + if (Server.zombie.Running && Server.zombie.Map == this) return Server.zombie; + if (Server.lava.Running && Server.lava.Map == this) return Server.lava; return null; } @@ -148,7 +146,6 @@ namespace MCGalaxy { public bool Unload(bool silent = false, bool save = true) { if (Server.mainLevel == this || IsMuseum) return false; - if (Server.lava.active && Server.lava.map == this) return false; OnLevelUnloadEvent.Call(this); if (cancelunload) { Logger.Log(LogType.SystemActivity, "Unload canceled by Plugin! (Map: {0})", name); diff --git a/MCGalaxy/MCGalaxy_.csproj b/MCGalaxy/MCGalaxy_.csproj index 09c14beca..8f7744ff1 100644 --- a/MCGalaxy/MCGalaxy_.csproj +++ b/MCGalaxy/MCGalaxy_.csproj @@ -486,32 +486,31 @@ + + - - - + + - - - + + + + - - - - - + + + - diff --git a/MCGalaxy/Network/Heartbeat/ClassiCube.cs b/MCGalaxy/Network/Heartbeat/ClassiCube.cs index 9bc9cf03a..67d5a1cc9 100644 --- a/MCGalaxy/Network/Heartbeat/ClassiCube.cs +++ b/MCGalaxy/Network/Heartbeat/ClassiCube.cs @@ -19,6 +19,7 @@ using System; using System.IO; using System.Net; using System.Net.Sockets; +using MCGalaxy.Events.ServerEvents; using Newtonsoft.Json; namespace MCGalaxy.Network { @@ -59,7 +60,7 @@ namespace MCGalaxy.Network { public override string GetHeartbeatData() { string name = ServerConfig.Name; - Server.zombie.OnHeartbeat(ref name); + OnSendingHeartbeatEvent.Call(this, ref name); name = Colors.Strip(name); return diff --git a/MCGalaxy/Player/Player.Fields.cs b/MCGalaxy/Player/Player.Fields.cs index a03441e41..03efe1a2a 100644 --- a/MCGalaxy/Player/Player.Fields.cs +++ b/MCGalaxy/Player/Player.Fields.cs @@ -243,7 +243,7 @@ namespace MCGalaxy { public bool cancelcommand, cancelchat, cancelmove, cancelBlock, cancelmysql; - public bool cancelmessage, cancellogin, cancelconnecting; + public bool cancelmessage, cancellogin, cancelconnecting, cancelDeath; /// Called when a player removes or places a block. /// NOTE: Currently this prevents the OnBlockChange event from being called. diff --git a/MCGalaxy/Player/Player.Handlers.cs b/MCGalaxy/Player/Player.Handlers.cs index be13d9159..cd2b66c3d 100644 --- a/MCGalaxy/Player/Player.Handlers.cs +++ b/MCGalaxy/Player/Player.Handlers.cs @@ -77,7 +77,7 @@ namespace MCGalaxy { RevertBlock(x, y, z); return; } - if ( Server.lava.active && Server.lava.HasPlayer(this) && Server.lava.IsPlayerDead(this) ) { + if ( Server.lava.running && Server.lava.Map == level && Server.lava.IsPlayerDead(this) ) { SendMessage("You are out of the round, and cannot build."); RevertBlock(x, y, z); return; } @@ -435,12 +435,13 @@ namespace MCGalaxy { bool Moved() { return lastRot.RotY != Rot.RotY || lastRot.HeadX != Rot.HeadX; } - public void HandleDeath(BlockID block, string customMsg = "", bool explode = false, bool immediate = false) { - OnPlayerDeathEvent.Call(this, block); + public bool HandleDeath(BlockID block, string customMsg = "", bool explode = false, bool immediate = false) { + if (!immediate && lastDeath.AddSeconds(2) > DateTime.UtcNow) return false; + if (invincible || hidden) return false; - if (Server.lava.active && Server.lava.HasPlayer(this) && Server.lava.IsPlayerDead(this)) return; - if (!immediate && lastDeath.AddSeconds(2) > DateTime.UtcNow) return; - if (!level.Config.KillerBlocks || invincible || hidden) return; + cancelDeath = false; + OnPlayerDeathEvent.Call(this, block); + if (cancelDeath) { cancelDeath = false; return false; } onTrain = false; trainInvincible = false; trainGrab = false; ushort x = (ushort)Pos.BlockX, y = (ushort)Pos.BlockY, z = (ushort)Pos.BlockZ; @@ -463,12 +464,7 @@ namespace MCGalaxy { if (PlayingTntWars) { TntWarsKillStreak = 0; - TntWarsScoreMultiplier = 1f; - } else if ( Server.lava.active && Server.lava.HasPlayer(this) ) { - if (!Server.lava.IsPlayerDead(this)) { - Server.lava.KillPlayer(this); - Command.all.FindByName("Spawn").Use(this, ""); - } + TntWarsScoreMultiplier = 1.0f; } else { Command.all.FindByName("Spawn").Use(this, ""); TimesDied++; @@ -476,9 +472,11 @@ namespace MCGalaxy { if (TimesDied > short.MaxValue) TimesDied = short.MaxValue; } - if (ServerConfig.AnnounceDeathCount && (TimesDied > 0 && TimesDied % 10 == 0)) + if (ServerConfig.AnnounceDeathCount && (TimesDied > 0 && TimesDied % 10 == 0)) { Chat.MessageLevel(this, ColoredName + " %Shas died &3" + TimesDied + " times", false, level); + } lastDeath = DateTime.UtcNow; + return true; } void HandleChat(byte[] buffer, int offset) { @@ -502,17 +500,6 @@ namespace MCGalaxy { // People who are muted can't speak or vote if (muted) { SendMessage("You are muted."); return; } //Muted: Only allow commands - // Lava Survival map vote recorder - if ( Server.lava.HasPlayer(this) && Server.lava.HasVote(text.ToLower()) ) { - if ( Server.lava.AddVote(this, text.ToLower()) ) { - SendMessage("Your vote for &5" + text.ToLower().Capitalize() + " %Shas been placed. Thanks!"); - Server.lava.map.ChatLevelOps(name + " voted for &5" + text.ToLower().Capitalize() + "%S."); - return; - } else { - SendMessage("&cYou already voted!"); - return; - } - } // Filter out bad words if (ServerConfig.ProfanityFiltering) text = ProfanityFilter.Parse(text); diff --git a/MCGalaxy/Player/Player.Login.cs b/MCGalaxy/Player/Player.Login.cs index 086b01041..05f3fe82f 100644 --- a/MCGalaxy/Player/Player.Login.cs +++ b/MCGalaxy/Player/Player.Login.cs @@ -148,7 +148,6 @@ namespace MCGalaxy { Logger.Log(LogType.UserActivity, "{0} [{1}] connected using {2}.", name, ip, appName); } Game.InfectMessages = PlayerDB.GetInfectMessages(this); - Server.lava.PlayerJoinedServer(this); Position pos = level.SpawnPos; byte yaw = level.rotx, pitch = level.roty; diff --git a/MCGalaxy/Player/Player.cs b/MCGalaxy/Player/Player.cs index f7988d4e2..b59e07c45 100644 --- a/MCGalaxy/Player/Player.cs +++ b/MCGalaxy/Player/Player.cs @@ -457,7 +457,7 @@ namespace MCGalaxy { // Mark callback cancelled selection if (selCallback == null) return; - selIndex++; + selIndex++; if (selIndex == 1 && selTitle != null) { SendCpeMessage(CpeMessageType.BottomRight2, "Mark #1" + FormatSelectionMark(selMarks[0])); } else if (selIndex == 2 && selTitle != null) { diff --git a/MCGalaxy/Player/PlayerPhysics.cs b/MCGalaxy/Player/PlayerPhysics.cs index 9e8a595e6..a5ae34eb2 100644 --- a/MCGalaxy/Player/PlayerPhysics.cs +++ b/MCGalaxy/Player/PlayerPhysics.cs @@ -51,7 +51,7 @@ namespace MCGalaxy.Blocks.Physics { if (!p.level.Props[block].KillerBlock) continue; if (block == Block.TNT_Explosion && p.PlayingTntWars) continue; // TODO: hardcoded behaviour is icky if (block == Block.Train && p.trainInvincible) continue; - p.HandleDeath(block); + if (p.level.Config.KillerBlocks) p.HandleDeath(block); } if (!hitWalkthrough) p.lastWalkthrough = -1; @@ -71,8 +71,9 @@ namespace MCGalaxy.Blocks.Physics { if (!CollideType.IsSolid(collide)) continue; int fallHeight = p.startFallY - bb.Min.Y; - if (fallHeight > p.level.Config.FallHeight * 32) + if (fallHeight > p.level.Config.FallHeight * 32) { p.HandleDeath(Block.Air, null, false, true); + } p.startFallY = -1; return; diff --git a/MCGalaxy/Server/Server.Fields.cs b/MCGalaxy/Server/Server.Fields.cs index 1c6c91d65..7a6c6317e 100644 --- a/MCGalaxy/Server/Server.Fields.cs +++ b/MCGalaxy/Server/Server.Fields.cs @@ -92,9 +92,9 @@ namespace MCGalaxy { public static ZSGame zombie; public static int YesVotes = 0, NoVotes = 0; - public static bool voting = false, votingforlevel = false; + public static bool voting = false; - public static LavaSurvival lava; + public static LSGame lava; public static CountdownGame Countdown; public static Scheduler MainScheduler = new Scheduler("MCG_MainScheduler"); diff --git a/MCGalaxy/Server/Server.cs b/MCGalaxy/Server/Server.cs index 7e2358e72..f74309a83 100644 --- a/MCGalaxy/Server/Server.cs +++ b/MCGalaxy/Server/Server.cs @@ -99,7 +99,7 @@ namespace MCGalaxy { MoveSqliteDll(); MoveOutdatedFiles(); - lava = new LavaSurvival(); + lava = new LSGame(); zombie = new ZSGame(); Countdown = new CountdownGame(); LoadAllSettings(); diff --git a/MCGalaxy/util/Math/Vectors.cs b/MCGalaxy/util/Math/Vectors.cs index 0ce738798..9017c2178 100644 --- a/MCGalaxy/util/Math/Vectors.cs +++ b/MCGalaxy/util/Math/Vectors.cs @@ -67,11 +67,12 @@ namespace MCGalaxy.Maths { public override string ToString() { - return X + "," + Y + "," + Z; + return X + ", " + Y + ", " + Z; } - public string ToString(string separator) { - return String.Format("{1}{0}{2}{0}{3}", separator, X, Y, Z); + public static Vec3U16 Parse(string input) { + string[] p = input.Replace(" ", "").Split(','); + return new Vec3U16(ushort.Parse(p[0]), ushort.Parse(p[1]), ushort.Parse(p[2])); } } @@ -166,14 +167,9 @@ namespace MCGalaxy.Maths { public static bool operator != (Vec3S32 a, Vec3S32 b) { return a.X != b.X || a.Y != b.Y || a.Z != b.Z; } - public override string ToString() { - return X + "," + Y + "," + Z; - } - - public string ToString(string separator) { - return String.Format("{1}{0}{2}{0}{3}", separator, X, Y, Z); + return X + ", " + Y + ", " + Z; } }