Mostly abstract level voting/picking code.

This commit is contained in:
UnknownShadow200 2017-08-06 15:52:08 +10:00
parent 90d19e62b8
commit e9c02198ce
22 changed files with 291 additions and 268 deletions

View File

@ -50,7 +50,7 @@ namespace MCGalaxy.Commands.Fun {
}
p.Game.PledgeSurvive = true;
Server.zombie.CurLevel
Server.zombie.Map
.ChatLevel(p.ColoredName + " %Spledges that they will not succumb to the infection!");
}

View File

@ -28,7 +28,7 @@ namespace MCGalaxy.Commands.Fun {
public override CommandEnable Enabled { get { return CommandEnable.Zombie; } }
public override void Use(Player p, string message) {
List<string> recent = Server.zombie.RecentMaps;
List<string> recent = Server.zombie.Picker.RecentMaps;
if (recent.Count == 0) {
Player.Message(p, "No maps have been used yet.");
} else {

View File

@ -36,16 +36,16 @@ namespace MCGalaxy.Commands.Fun {
Player.Message(p, value + " was queued.");
Server.zombie.QueuedZombie = who.name;
if (Server.zombie.CurLevel != null)
Server.zombie.CurLevel.ChatLevel(who.ColoredName + " %Swas queued as the next zombie.");
if (Server.zombie.Map != null)
Server.zombie.Map.ChatLevel(who.ColoredName + " %Swas queued as the next zombie.");
} else if (args[0].CaselessEq("level")) {
string map = Matcher.FindMaps(p, value);
if (map == null) return;
Player.Message(p, map + " was queued.");
Server.zombie.QueuedLevel = map.ToLower();
if (Server.zombie.CurLevel != null)
Server.zombie.CurLevel.ChatLevel(map + " was queued as the next map.");
Server.zombie.Picker.QueuedMap = map.ToLower();
if (Server.zombie.Map != null)
Server.zombie.Map.ChatLevel(map + " was queued as the next map.");
} else {
Help(p);
}

View File

@ -28,7 +28,7 @@ namespace MCGalaxy.Commands.Fun {
public override CommandEnable Enabled { get { return CommandEnable.Zombie; } }
public override void Use(Player p, string message) {
ShowQueued(p, Server.zombie.QueuedLevel, "level");
ShowQueued(p, Server.zombie.Picker.QueuedMap, "level");
ShowQueued(p, Server.zombie.QueuedZombie, "zombie");
}

View File

@ -50,7 +50,7 @@ namespace MCGalaxy.Commands.Fun {
if (game.Status == ZombieGameStatus.NotStarted) {
Player.Message(p, "Zombie Survival is not currently running."); return;
}
PlayerActions.ChangeMap(p, game.CurLevel);
PlayerActions.ChangeMap(p, game.Map);
}
static void HandleStatus(Player p, ZSGame game, string[] args) {
@ -67,8 +67,8 @@ namespace MCGalaxy.Commands.Fun {
Player.Message(p, "Zombie Survival game currently in progress, with this round being the final round."); break;
}
if (game.Status == ZombieGameStatus.NotStarted || game.CurLevelName.Length == 0) return;
Player.Message(p, "Running on map: " + game.CurLevelName);
if (game.Status == ZombieGameStatus.NotStarted || game.MapName.Length == 0) return;
Player.Message(p, "Running on map: " + game.MapName);
}
static void HandleStart(Player p, ZSGame game, string[] args) {
@ -103,9 +103,9 @@ namespace MCGalaxy.Commands.Fun {
}
string src = p == null ? "(console)" : p.ColoredName;
Level lvl = game.CurLevel;
Level lvl = game.Map;
if (lvl != null) {
Chat.MessageLevel(game.CurLevel, "Zombie Survival was stopped by " + src);
Chat.MessageLevel(game.Map, "Zombie Survival was stopped by " + src);
}
src = p == null ? "(console)" : p.name;

View File

@ -61,9 +61,9 @@ namespace MCGalaxy.Eco {
int chance = new Random().Next(1, 101);
if (chance <= ZSConfig.ReviveChance) {
Server.zombie.DisinfectPlayer(p);
Server.zombie.CurLevel.ChatLevel(p.ColoredName + " %S" + ZSConfig.ReviveSuccessMessage);
Server.zombie.Map.ChatLevel(p.ColoredName + " %S" + ZSConfig.ReviveSuccessMessage);
} else {
Server.zombie.CurLevel.ChatLevel(p.ColoredName + " %S" + ZSConfig.ReviveFailureMessage);
Server.zombie.Map.ChatLevel(p.ColoredName + " %S" + ZSConfig.ReviveFailureMessage);
}
Economy.MakePurchase(p, Price, "%3Revive:");
p.Game.RevivesUsed++;

View File

@ -64,7 +64,7 @@ namespace MCGalaxy.Eco {
public override string Name { get { return "QueueLevel"; } }
protected override void DoPurchase(Player p, string message, string[] args) {
if (Server.zombie.QueuedLevel != null) {
if (Server.zombie.Picker.QueuedMap != null) {
Player.Message(p, "Someone else has already queued a level."); return;
}
string map = Matcher.FindMaps(p, args[1]);
@ -157,7 +157,7 @@ namespace MCGalaxy.Eco {
int left = MaxPotions - p.Game.InvisibilityPotions;
Player.Message(p, "Lasts for &a{0} %Sseconds. You can buy &a{1} %Smore this round.", Duration, left);
Server.zombie.CurLevel.ChatLevel(p.ColoredName + " %Svanished. &a*POOF*");
Server.zombie.Map.ChatLevel(p.ColoredName + " %Svanished. &a*POOF*");
Entities.GlobalDespawn(p, false);
Economy.MakePurchase(p, Price, "%3Invisibility: " + Duration);
}

View File

@ -34,7 +34,7 @@ namespace MCGalaxy.Games {
public CtfData(Player p) { this.p = p; }
}
public sealed partial class CTFGame {
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;
@ -42,7 +42,6 @@ namespace MCGalaxy.Games {
public bool started = false;
public CtfTeam2 Red, Blue;
public Level Map;
List<CtfData> cache = new List<CtfData>();
public CTFConfig Config = new CTFConfig();
@ -70,6 +69,7 @@ namespace MCGalaxy.Games {
/// <summary> Load a map into CTF </summary>
public void SetMap(string mapName) {
MapName = mapName;
CmdLoad.LoadLevel(null, mapName);
Map = LevelInfo.FindExact(mapName);
Map.SaveChanges = false;
@ -141,8 +141,8 @@ namespace MCGalaxy.Games {
if (started) {
Player.Message(p, "CTF game already running."); return false;
}
List<string> maps = GetCtfMaps();
List<string> maps = GetCtfMaps();
if (maps.Count == 0) {
Player.Message(p, "No CTF maps were found."); return false;
}

View File

@ -29,9 +29,6 @@ namespace MCGalaxy.Games {
/// <summary> Players who are still alive in the current round. </summary>
public VolatileArray<Player> Remaining = new VolatileArray<Player>();
/// <summary> Map countdown is running on. </summary>
public Level Map;
/// <summary> Current status of the countdown game. </summary>
public CountdownGameStatus Status = CountdownGameStatus.Disabled;
@ -323,6 +320,7 @@ namespace MCGalaxy.Games {
plugin.Game = this;
plugin.Load(false);
MapName = "countdown";
CmdLoad.LoadLevel(null, "countdown");
Map = LevelInfo.FindExact("countdown");

View File

@ -21,6 +21,12 @@ namespace MCGalaxy.Games {
public abstract class IGame {
/// <summary> Name of the map this game is running on. </summary>
public string MapName;
/// <summary> Level instance of the map this game is running on. </summary>
public Level Map;
/// <summary> Whether players are allowed to teleport to others when not in referee mode. </summary>
public virtual bool TeleportAllowed { get { return true; } }

View File

@ -0,0 +1,151 @@
/*
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.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;
using System.Threading;
namespace MCGalaxy.Games {
public abstract class LevelPicker {
/// <summary> Level specifically chosen to be used in the next round. </summary>
public string QueuedMap;
/// <summary> List of maps that have been recently played in this game. </summary>
public List<string> RecentMaps = new List<string>();
internal string Candidate1 = "", Candidate2 = "", Candidate3 = "";
internal int Votes1 = 0, Votes2 = 0, Votes3 = 0;
public string ChooseNextLevel(ZSGame game) {
if (QueuedMap != null) return QueuedMap;
try {
List<string> maps = GetCandidateLevels();
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);
if (!game.Running) return null;
DoLevelVote(game);
if (!game.Running) return null;
return NextLevel(r, maps, game);
} catch (Exception ex) {
Logger.LogError(ex);
return null;
}
}
void RemoveRecentLevels(List<string> maps) {
// Try to avoid recently played levels, avoiding most recent
List<string> recent = RecentMaps;
for (int i = recent.Count - 1; i >= 0; i--) {
if (maps.Count > 3 && maps.CaselessContains(recent[i]))
maps.CaselessRemove(recent[i]);
}
// Try to avoid maps voted last round if possible
if (maps.Count > 3) maps.CaselessRemove(Candidate1);
if (maps.Count > 3) maps.CaselessRemove(Candidate2);
if (maps.Count > 3) maps.CaselessRemove(Candidate3);
}
void DoLevelVote(IGame game) {
Server.votingforlevel = true;
Player[] players = PlayerInfo.Online.Items;
foreach (Player pl in players) {
if (pl.level != game.Map) continue;
SendVoteMessage(pl);
}
VoteCountdown(game);
Server.votingforlevel = false;
}
void VoteCountdown(IGame game) {
// Show message for non-CPE clients
Player[] players = PlayerInfo.Online.Items;
foreach (Player pl in players) {
if (pl.level != game.Map || pl.HasCpeExt(CpeExt.MessageTypes)) continue;
pl.SendMessage("You have 20 seconds to vote for the next map");
}
for (int i = 0; i < 20; i++) {
players = PlayerInfo.Online.Items;
foreach (Player pl in players) {
if (pl.level != game.Map || !pl.HasCpeExt(CpeExt.MessageTypes)) continue;
pl.SendCpeMessage(CpeMessageType.BottomRight1, "&e" + (20 - i) + "s %Sleft to vote");
}
Thread.Sleep(1000);
}
}
string NextLevel(Random r, List<string> levels, ZSGame game) {
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;
}
} else {
if (Votes3 > Votes1 && Votes3 > Votes2) {
return Candidate3;
} else {
return Candidate2;
}
}
}
internal static string GetRandomLevel(Random r, List<string> maps) {
int i = r.Next(0, maps.Count);
string map = maps[i];
maps.RemoveAt(i);
return map;
}
/// <summary> Returns a list of maps that can be used for a round of this game. </summary>
/// <returns> null if not enough levels are available, otherwise the list of levels. </returns>
public abstract List<string> GetCandidateLevels();
/// <summary> Sends the formatted vote message to the player (using bottom right if supported) </summary>
public void SendVoteMessage(Player p) {
const string line1 = "&eLevel vote - type &a1&e, &b2&e or &c3";
string line2 = "&a" + Candidate1 + "&e, &b" + Candidate2 + "&e, &c" + Candidate3;
if (p.HasCpeExt(CpeExt.MessageTypes)) {
p.SendCpeMessage(CpeMessageType.BottomRight3, line1);
p.SendCpeMessage(CpeMessageType.BottomRight2, line2);
} else {
Player.Message(p, line1);
Player.Message(p, line2);
}
}
}
}

View File

@ -70,16 +70,16 @@ 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.CurLevelName, timespan);
return String.Format(format, game.Alive.Count, game.MapName, timespan);
} else {
const string format = "&a{0} %Salive %S(map: {1})";
return String.Format(format, game.Alive.Count, game.CurLevelName);
return String.Format(format, game.Alive.Count, game.MapName);
}
}
static string FormatSecondary(ZSGame game) {
string pillar = "%SPillaring " + (game.CurLevel.Config.Pillaring ? "&aYes" : "&cNo");
string type = "%S, Type is &a" + game.CurLevel.Config.BuildType;
string pillar = "%SPillaring " + (game.Map.Config.Pillaring ? "&aYes" : "&cNo");
string type = "%S, Type is &a" + game.Map.Config.BuildType;
return pillar + type;
}
@ -93,7 +93,7 @@ namespace MCGalaxy.Games.ZS {
if (!game.Running) return;
Player[] online = PlayerInfo.Online.Items;
foreach (Player p in online) {
if (!p.level.name.CaselessEq(game.CurLevelName)) continue;
if (!p.level.name.CaselessEq(game.MapName)) continue;
p.SendCpeMessage(type, message);
}
}

View File

@ -19,123 +19,18 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
namespace MCGalaxy.Games.ZS {
internal static class LevelPicker {
internal class ZSLevelPicker : LevelPicker {
internal static void ChooseNextLevel(ZSGame game) {
if (game.QueuedLevel != null) { game.ChangeLevel(game.QueuedLevel); return; }
if (!ZSConfig.ChangeLevels) return;
try {
List<string> maps = GetCandidateLevels();
if (maps == null) return;
RemoveRecentLevels(maps, game);
game.Votes1 = 0; game.Votes2 = 0; game.Votes3 = 0;
Random r = new Random();
game.Candidate1 = GetRandomLevel(r, maps);
game.Candidate2 = GetRandomLevel(r, maps);
game.Candidate3 = GetRandomLevel(r, maps);
if (!game.Running || game.Status == ZombieGameStatus.LastRound) return;
DoLevelVote(game);
if (!game.Running || game.Status == ZombieGameStatus.LastRound) return;
MoveToNextLevel(r, maps, game);
} catch (Exception ex) {
Logger.LogError(ex);
}
}
static void RemoveRecentLevels(List<string> maps, ZSGame game) {
// Try to avoid recently played levels, avoiding most recent
List<string> recent = game.RecentMaps;
for (int i = recent.Count - 1; i >= 0; i--) {
if (maps.Count > 3 && maps.CaselessContains(recent[i]))
maps.CaselessRemove(recent[i]);
}
// Try to avoid maps voted last round if possible
if (maps.Count > 3 && maps.CaselessContains(game.Candidate1))
maps.CaselessRemove(game.Candidate1);
if (maps.Count > 3 && maps.CaselessContains(game.Candidate2))
maps.CaselessRemove(game.Candidate2);
if (maps.Count > 3 && maps.CaselessContains(game.Candidate3))
maps.CaselessRemove(game.Candidate3);
}
static void DoLevelVote(ZSGame game) {
Server.votingforlevel = true;
Player[] players = PlayerInfo.Online.Items;
foreach (Player pl in players) {
if (pl.level != game.CurLevel) continue;
SendVoteMessage(pl, game);
}
VoteCountdown(game);
Server.votingforlevel = false;
}
static void VoteCountdown(ZSGame game) {
// Show message for non-CPE clients
Player[] players = PlayerInfo.Online.Items;
foreach (Player pl in players) {
if (pl.level != game.CurLevel || pl.HasCpeExt(CpeExt.MessageTypes)) continue;
pl.SendMessage("You have 20 seconds to vote for the next map");
}
for (int i = 0; i < 20; i++) {
players = PlayerInfo.Online.Items;
foreach (Player pl in players) {
if (pl.level != game.CurLevel || !pl.HasCpeExt(CpeExt.MessageTypes)) continue;
pl.SendCpeMessage(CpeMessageType.BottomRight1, "&e" + (20 - i) + "s %Sleft to vote");
}
Thread.Sleep(1000);
}
}
/// <summary> Moves all players to the level which has the highest number of votes. </summary>
static void MoveToNextLevel(Random r, List<string> levels, ZSGame game) {
int v1 = game.Votes1, v2 = game.Votes2, v3 = game.Votes3;
if (v1 >= v2) {
if (v3 > v1 && v3 > v2) {
game.ChangeLevel(game.Candidate3);
} else {
game.ChangeLevel(game.Candidate1);
}
} else {
if (v3 > v1 && v3 > v2) {
game.ChangeLevel(game.Candidate3);
} else {
game.ChangeLevel(game.Candidate2);
}
}
Player[] online = PlayerInfo.Online.Items;
foreach (Player pl in online)
pl.voted = false;
}
internal static string GetRandomLevel(Random r, List<string> maps) {
int i = r.Next(0, maps.Count);
string map = maps[i];
maps.RemoveAt(i);
return map;
}
/// <summary> Returns a list of maps that can be used for a round of zombie survival. </summary>
/// <returns> null if not enough levels are available, otherwise the list of levels. </returns>
internal static List<string> GetCandidateLevels() {
public override List<string> GetCandidateLevels() {
List<string> maps = null;
if (ZSConfig.LevelList.Count > 0) {
maps = new List<string>(ZSConfig.LevelList);
} else {
maps = GetAllMaps();
maps = AllMaps();
}
foreach (string ignore in ZSConfig.IgnoredLevelList)
maps.Remove(ignore);
@ -153,32 +48,16 @@ namespace MCGalaxy.Games.ZS {
}
/// <summary> Returns a list of all possible maps (exclusing personal realms if 'ignore realms' setting is true) </summary>
internal static List<string> GetAllMaps() {
static List<string> AllMaps() {
List<string> maps = new List<string>();
string[] files = LevelInfo.AllMapFiles();
foreach (string file in files) {
string name = Path.GetFileNameWithoutExtension(file);
if (name.IndexOf('+') >= 0 && ZSConfig.IgnorePersonalWorlds)
continue;
maps.Add(name);
string map = Path.GetFileNameWithoutExtension(file);
if (map.IndexOf('+') >= 0 && ZSConfig.IgnorePersonalWorlds) continue;
maps.Add(map);
}
return maps;
}
/// <summary> Sends the formatted vote message to the player (using bottom right if supported) </summary>
internal static void SendVoteMessage(Player p, ZSGame game) {
const string line1 = "&eLevel vote - type &a1&e, &b2&e or &c3";
string line2 = "&a" + game.Candidate1 + "&e, &b"
+ game.Candidate2 + "&e, &c" + game.Candidate3;
if (p.HasCpeExt(CpeExt.MessageTypes)) {
p.SendCpeMessage(CpeMessageType.BottomRight3, line1);
p.SendCpeMessage(CpeMessageType.BottomRight2, line2);
} else {
Player.Message(p, line1);
Player.Message(p, line2);
}
}
}
}

View File

@ -27,8 +27,8 @@ namespace MCGalaxy.Games.ZS {
internal static bool Handles(Player p, ushort x, ushort y, ushort z,
bool placing, ExtBlock block, ExtBlock old, ZSGame game) {
if (placing && !game.CurLevel.Config.Pillaring && !p.Game.Referee) {
if (NotPillaring(game.CurLevel, block, old)) {
if (placing && !game.Map.Config.Pillaring && !p.Game.Referee) {
if (NotPillaring(game.Map, block, old)) {
p.Game.BlocksStacked = 0;
} else if (CheckCoords(p, x, y, z)) {
p.Game.BlocksStacked++;

View File

@ -25,16 +25,16 @@ namespace MCGalaxy.Games.ZS {
public static void HandOut(ZSGame game) {
Player[] alive = game.Alive.Items, dead = game.Infected.Items;
game.CurLevel.ChatLevel("&aThe game has ended!");
game.Map.ChatLevel("&aThe game has ended!");
if (alive.Length == 0) game.CurLevel.ChatLevel("&4Zombies have won this round.");
else if (alive.Length == 1) game.CurLevel.ChatLevel("&2Congratulations to the sole survivor:");
else game.CurLevel.ChatLevel("&2Congratulations to the survivors:");
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.CurLevel.Config.RoundsPlayed++;
game.Map.Config.RoundsPlayed++;
if (alive.Length > 0) {
game.CurLevel.Config.RoundsHumanWon++;
game.Map.Config.RoundsHumanWon++;
foreach (Player p in alive)
IncreaseAliveStats(p, game);
}
@ -45,7 +45,7 @@ namespace MCGalaxy.Games.ZS {
static void AnnounceWinners(ZSGame game, Player[] alive, Player[] dead) {
if (alive.Length > 0) {
string winners = alive.Join(p => p.ColoredName);
game.CurLevel.ChatLevel(winners);
game.Map.ChatLevel(winners);
return;
}
@ -61,7 +61,7 @@ namespace MCGalaxy.Games.ZS {
string suffix = maxKills == 1 ? " %Skill" : " %Skills";
StringFormatter<Player> formatter = p => p.Game.CurrentInfected == maxKills ? p.ColoredName : null;
game.CurLevel.ChatLevel("&8Best" + group + "%S(&b" + maxKills
game.Map.ChatLevel("&8Best" + group + "%S(&b" + maxKills
+ suffix + "%S)&8: " + dead.Join(formatter));
}
@ -83,7 +83,7 @@ namespace MCGalaxy.Games.ZS {
Random rand = new Random();
foreach (Player pl in online) {
if (!pl.level.name.CaselessEq(game.CurLevelName)) continue;
if (!pl.level.name.CaselessEq(game.MapName)) continue;
pl.Game.ResetInvisibility();
int reward = GetMoneyReward(pl, alive, rand);

View File

@ -53,7 +53,7 @@ namespace MCGalaxy.Games.ZS {
void HandleTabListEntryAdded(Entity entity, ref string tabName, ref string tabGroup, Player dst) {
Player p = entity as Player;
if (p == null || p.level != Game.CurLevel) return;
if (p == null || p.level != Game.Map) return;
if (p.Game.Referee) {
tabGroup = "&2Referees";
@ -70,7 +70,7 @@ namespace MCGalaxy.Games.ZS {
}
void HandleMoneyChanged(Player p) {
if (p.level != Game.CurLevel) return;
if (p.level != Game.Map) return;
HUD.UpdateTertiary(p);
}
@ -84,7 +84,7 @@ namespace MCGalaxy.Games.ZS {
}
void HandlePlayerMove(Player p, Position next, byte rotX, byte rotY) {
if (!Game.RoundInProgress || p.level != Game.CurLevel) return;
if (!Game.RoundInProgress || p.level != Game.Map) return;
bool reverted = MovementCheck.DetectNoclip(p, next)
|| MovementCheck.DetectSpeedhack(p, next, ZSConfig.MaxMoveDistance);
@ -93,10 +93,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.CurLevel) return;
if (p.level != Game.Map) return;
if (action == PlayerAction.UnReferee) {
Game.PlayerJoinedLevel(p, Game.CurLevel, Game.CurLevel);
Game.PlayerJoinedLevel(p, Game.Map, Game.Map);
Command.all.FindByName("Spawn").Use(p, "");
p.Game.Referee = false;
@ -117,7 +117,7 @@ namespace MCGalaxy.Games.ZS {
}
void HandlePlayerSpawning(Player p, ref Position pos, ref byte yaw, ref byte pitch, bool respawning) {
if (p.level != Game.CurLevel) return;
if (p.level != Game.Map) return;
if (!p.Game.Referee && !p.Game.Infected && Game.RoundInProgress) {
Game.InfectPlayer(p, null);
@ -125,13 +125,13 @@ namespace MCGalaxy.Games.ZS {
}
void HandleBlockChange(Player p, ushort x, ushort y, ushort z, ExtBlock block, bool placing) {
if (p.level != Game.CurLevel) return;
ExtBlock old = Game.CurLevel.GetBlock(x, y, z);
if (p.level != Game.Map) return;
ExtBlock old = Game.Map.GetBlock(x, y, z);
if (Game.CurLevel.Config.BuildType == BuildType.NoModify) {
if (Game.Map.Config.BuildType == BuildType.NoModify) {
p.RevertBlock(x, y, z); p.cancelBlock = true; return;
}
if (Game.CurLevel.Config.BuildType == BuildType.ModifyOnly && Game.CurLevel.BlockProps[old.Index].OPBlock) {
if (Game.Map.Config.BuildType == BuildType.ModifyOnly && Game.Map.BlockProps[old.Index].OPBlock) {
p.RevertBlock(x, y, z); p.cancelBlock = true; return;
}

View File

@ -51,8 +51,7 @@ namespace MCGalaxy.Games {
return;
} else if (Status == ZombieGameStatus.InfiniteRounds) {
DoRound();
if (ZSConfig.ChangeLevels)
LevelPicker.ChooseNextLevel(this);
MoveToNextLevel();
} else if (Status == ZombieGameStatus.SingleRound) {
DoRound();
End(); return;
@ -61,14 +60,19 @@ namespace MCGalaxy.Games {
End(); return;
} else {
DoRound();
if (ZSConfig.ChangeLevels)
LevelPicker.ChooseNextLevel(this);
MoveToNextLevel();
}
} else if (Status == ZombieGameStatus.LastRound) {
End(); return;
}
}
}
void MoveToNextLevel() {
if (!ZSConfig.ChangeLevels) return;
string map = Picker.ChooseNextLevel(this);
if (map != null) ChangeLevel(map);
}
void DoRound() {
if (!Running) return;
@ -77,29 +81,29 @@ namespace MCGalaxy.Games {
Random random = new Random();
RoundInProgress = true;
int roundMins = random.Next(CurLevel.Config.MinRoundTime, CurLevel.Config.MaxRoundTime);
int roundMins = random.Next(Map.Config.MinRoundTime, Map.Config.MaxRoundTime);
string suffix = roundMins == 1 ? " %Sminute!" : " %Sminutes!";
CurLevel.ChatLevel("This round will last for &a" + roundMins + suffix);
Map.ChatLevel("This round will last for &a" + roundMins + suffix);
RoundEnd = DateTime.UtcNow.AddMinutes(roundMins);
Player[] online = PlayerInfo.Online.Items;
foreach (Player p in online) {
if (p.level == null || p.level != CurLevel || p.Game.Referee) continue;
if (p.level == null || p.level != Map || p.Game.Referee) continue;
Alive.Add(p);
}
Infected.Clear();
Player first = PickFirstZombie(random, players);
CurLevel.ChatLevel("&c" + first.DisplayName + " %Sstarted the infection!");
Map.ChatLevel("&c" + first.DisplayName + " %Sstarted the infection!");
InfectPlayer(first, null);
DoCoreGame(random);
if (!Running) { Status = ZombieGameStatus.LastRound; return; }
EndRound();
if (RecentMaps.Count > 20)
RecentMaps.RemoveAt(0);
RecentMaps.Add(CurLevelName);
if (Picker.RecentMaps.Count > 20)
Picker.RecentMaps.RemoveAt(0);
Picker.RecentMaps.Add(MapName);
}
Player PickFirstZombie(Random random, List<Player> players) {
@ -108,7 +112,7 @@ namespace MCGalaxy.Games {
first = QueuedZombie != null ?
PlayerInfo.FindExact(QueuedZombie) : players[random.Next(players.Count)];
QueuedZombie = null;
} while (first == null || !first.level.name.CaselessEq(CurLevelName));
} while (first == null || !first.level.name.CaselessEq(MapName));
return first;
}
@ -138,7 +142,7 @@ namespace MCGalaxy.Games {
Player[] online = PlayerInfo.Online.Items;
foreach (Player p in online) {
if (!p.Game.Referee && p.level.name.CaselessEq(CurLevelName)) {
if (!p.Game.Referee && p.level.name.CaselessEq(MapName)) {
players.Add(p);
nonRefPlayers++;
}
@ -146,7 +150,7 @@ namespace MCGalaxy.Games {
if (!Running) return null;
if (nonRefPlayers >= 2) return players;
CurLevel.ChatLevel("&cNeed 2 or more non-ref players to start a round.");
Map.ChatLevel("&cNeed 2 or more non-ref players to start a round.");
}
}
@ -198,8 +202,8 @@ namespace MCGalaxy.Games {
if (killer.Game.Infected && !alive.Game.Infected
&& !alive.Game.Referee && !killer.Game.Referee
&& killer.level.name.CaselessEq(CurLevelName)
&& alive.level.name.CaselessEq(CurLevelName))
&& killer.level.name.CaselessEq(MapName)
&& alive.level.name.CaselessEq(MapName))
{
InfectPlayer(alive, killer);
alive.Game.LastInfecter = killer.name;
@ -209,7 +213,7 @@ namespace MCGalaxy.Games {
if (infectCombo >= 2) {
killer.SendMessage("You gained " + (2 + infectCombo) + " " + ServerConfig.Currency);
killer.SetMoney(killer.money + (2 + infectCombo));
CurLevel.ChatLevel("&c" + killer.DisplayName + " %Sis on a rampage! " + (infectCombo + 1) + " infections in a row!");
Map.ChatLevel("&c" + killer.DisplayName + " %Sis on a rampage! " + (infectCombo + 1) + " infections in a row!");
}
} else {
infectCombo = 0;
@ -231,7 +235,7 @@ namespace MCGalaxy.Games {
void SendLevelRaw(string message, bool announce = false) {
Player[] players = PlayerInfo.Online.Items;
foreach (Player p in players) {
if (p.level != CurLevel) continue;
if (p.level != Map) continue;
CpeMessageType type = announce && p.HasCpeExt(CpeExt.MessageTypes)
? CpeMessageType.Announcement : CpeMessageType.Normal;
@ -243,7 +247,7 @@ namespace MCGalaxy.Games {
DateTime now = DateTime.UtcNow;
Player[] players = PlayerInfo.Online.Items;
foreach (Player p in players) {
if (!p.Game.Invisible || p.level != CurLevel) continue;
if (!p.Game.Invisible || p.level != Map) continue;
DateTime end = p.Game.InvisibilityEnd;
if (now >= end) {
Player.Message(p, "&cYou are &bvisible &cagain");
@ -267,7 +271,7 @@ namespace MCGalaxy.Games {
void CheckHumanPledge(Player p, Player killer) {
if (!p.Game.PledgeSurvive) return;
p.Game.PledgeSurvive = false;
CurLevel.ChatLevel("&c" + p.DisplayName + " %Sbroke their pledge of not being infected.");
Map.ChatLevel("&c" + p.DisplayName + " %Sbroke their pledge of not being infected.");
if (killer == null) {
Player.Message(p, "As this was an automatic infection, you have not lost any &3" + ServerConfig.Currency);
@ -283,12 +287,12 @@ namespace MCGalaxy.Games {
Player setter = PlayerInfo.FindExact(bounty.Origin);
if (pKiller == null) {
CurLevel.ChatLevel("Bounty on " + p.ColoredName + " %Sis no longer active.");
Map.ChatLevel("Bounty on " + p.ColoredName + " %Sis no longer active.");
if (setter != null) setter.SetMoney(setter.money + bounty.Amount);
} else if (setter == null) {
Player.Message(pKiller, "Cannot collect the bounty, as the player who set it is offline.");
} else {
CurLevel.ChatLevel("&c" + pKiller.DisplayName + " %Scollected the bounty of &a" +
Map.ChatLevel("&c" + pKiller.DisplayName + " %Scollected the bounty of &a" +
bounty.Amount + " %S" + ServerConfig.Currency + " on " + p.ColoredName + "%S.");
pKiller.SetMoney(pKiller.money + bounty.Amount);
}
@ -303,7 +307,7 @@ namespace MCGalaxy.Games {
text = infectMessages[random.Next(infectMessages.Count)];
}
CurLevel.ChatLevel(String.Format(text,
Map.ChatLevel(String.Format(text,
"&c" + pKiller.DisplayName + "%S",
pAlive.ColoredName + "%S"));
}

View File

@ -23,6 +23,7 @@ namespace MCGalaxy.Games {
public sealed partial class ZSGame : IGame {
public LevelPicker Picker = new ZSLevelPicker();
/// <summary> Whether players are allowed to teleport to others when not in referee mode. </summary>
public override bool TeleportAllowed { get { return !RoundInProgress; } }
@ -37,7 +38,7 @@ namespace MCGalaxy.Games {
}
public override bool HandlesChatMessage(Player p, string message) {
if (!Running || (p.level == null || !p.level.name.CaselessEq(CurLevelName))) return false;
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) {
@ -45,7 +46,7 @@ namespace MCGalaxy.Games {
string type = p.Game.Infected ? " &cto zombies%S: " : " &ato humans%S: ";
foreach (Player pl in players) {
if (!pl.level.name.CaselessEq(CurLevelName)) continue;
if (!pl.level.name.CaselessEq(MapName)) continue;
if (pl.Game.Referee || pl.Game.Infected == p.Game.Infected)
pl.SendMessage(p.ColoredName + type + message.Substring(1));
}
@ -62,9 +63,9 @@ namespace MCGalaxy.Games {
bool HandleVote(Player p, string message) {
message = message.ToLower();
if (Player.CheckVote(message, p, "1", "one", ref Votes1) ||
Player.CheckVote(message, p, "2", "two", ref Votes2) ||
Player.CheckVote(message, p, "3", "three", ref Votes3))
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;
}
@ -75,7 +76,7 @@ namespace MCGalaxy.Games {
if (!(b.Origin.CaselessEq(p.name) || b.Target.CaselessEq(p.name))) continue;
string target = PlayerInfo.GetColoredName(p, b.Target);
CurLevel.ChatLevel("Bounty on " + target + " %Sis no longer active.");
Map.ChatLevel("Bounty on " + target + " %Sis no longer active.");
Bounties.Remove(b);
Player setter = PlayerInfo.FindExact(b.Origin);
@ -87,27 +88,27 @@ namespace MCGalaxy.Games {
p.SendCpeMessage(CpeMessageType.BottomRight3, "");
p.SendCpeMessage(CpeMessageType.BottomRight2, "");
p.SendCpeMessage(CpeMessageType.BottomRight1, "");
if (RoundInProgress && lvl.name.CaselessEq(CurLevelName)) {
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 == CurLevel) {
if (RoundInProgress && oldLvl == Map) {
PlayerLeftGame(p);
}
if (lvl.name.CaselessEq(CurLevelName)) {
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" + CurLevel.Config.Likes +
" likes %Sand &c" + CurLevel.Config.Dislikes + " dislikes");
Player.Message(p, "This map's win chance is &a" + CurLevel.WinChance + "%S%");
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 (CurLevel.Config.Authors.Length > 0) {
string[] authors = CurLevel.Config.Authors.Replace(" ", "").Split(',');
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)));
}
@ -116,8 +117,7 @@ namespace MCGalaxy.Games {
HUD.UpdateSecondary(this, p);
HUD.UpdateTertiary(p);
if (Server.votingforlevel)
LevelPicker.SendVoteMessage(p, this);
if (Server.votingforlevel) Picker.SendVoteMessage(p);
return;
}
@ -125,13 +125,13 @@ namespace MCGalaxy.Games {
HUD.Reset(p);
Alive.Remove(p);
Infected.Remove(p);
if (oldLvl != null && oldLvl.name.CaselessEq(CurLevelName))
if (oldLvl != null && oldLvl.name.CaselessEq(MapName))
HUD.UpdateAllPrimary(this);
}
public override void OnHeartbeat(ref string name) {
if (!Running || !ZSConfig.IncludeMapInHeartbeat || CurLevelName == null) return;
name += " (map: " + CurLevelName + ")";
if (!Running || !ZSConfig.IncludeMapInHeartbeat || MapName == null) return;
name += " (map: " + MapName + ")";
}
public override void AdjustPrefix(Player p, ref string prefix) {

View File

@ -63,34 +63,19 @@ namespace MCGalaxy.Games {
/// <summary> The name of the level that the last round of zombie survival was played on. </summary>
public string LastLevelName = "";
/// <summary> The name of the level that the current round of zombie survival is being played on. </summary>
public string CurLevelName = "";
/// <summary> The level that the current round of zombie survival is being played on. </summary>
public Level CurLevel = null;
/// <summary> List of alive/human players. </summary>
public VolatileArray<Player> Alive = new VolatileArray<Player>();
/// <summary> List of dead/infected players. </summary>
public VolatileArray<Player> Infected = new VolatileArray<Player>();
public List<string> RecentMaps = new List<string>();
/// <summary> Name of the player queued to be the first zombie in the next round. </summary>
public string QueuedZombie;
/// <summary> Name of the level queued to be used for the next round. </summary>
public string QueuedLevel;
List<string> infectMessages = new List<string>();
internal string Candidate1 = "", Candidate2 = "", Candidate3 = "";
internal int Votes1 = 0, Votes2 = 0, Votes3 = 0;
string lastPlayerToInfect = "";
int infectCombo = 0;
int infectCombo = 0;
/// <summary> List of players who have a bounty on them. </summary>
public VolatileArray<BountyData> Bounties = new VolatileArray<BountyData>();

View File

@ -52,28 +52,28 @@ namespace MCGalaxy.Games {
bool SetStartLevel(Level level) {
if (level == null) {
List<string> levels = LevelPicker.GetCandidateLevels();
List<string> levels = Picker.GetCandidateLevels();
if (levels == null) return false;
CurLevelName = LevelPicker.GetRandomLevel(new Random(), levels);
CurLevel = LevelInfo.FindExact(CurLevelName)
?? CmdLoad.LoadLevel(null, CurLevelName);
if (CurLevel == null) return false;
MapName = LevelPicker.GetRandomLevel(new Random(), levels);
Map = LevelInfo.FindExact(MapName)
?? CmdLoad.LoadLevel(null, MapName);
if (Map == null) return false;
} else {
CurLevelName = level.name;
CurLevel = level;
MapName = level.name;
Map = level;
}
CurLevel.SaveChanges = false;
Chat.MessageGlobal("A game of zombie survival is starting on: {0}", CurLevelName);
Map.SaveChanges = false;
Chat.MessageGlobal("A game of zombie survival is starting on: {0}", MapName);
Player[] players = PlayerInfo.Online.Items;
foreach (Player p in players) {
if (p.level != CurLevel) continue;
if (p.level != Map) continue;
PlayerJoinedLevel(p, p.level, p.level);
}
if (ZSConfig.SetMainLevel)
Server.mainLevel = CurLevel;
Server.mainLevel = Map;
return true;
}
@ -85,7 +85,7 @@ namespace MCGalaxy.Games {
if (alive.Length == 0) return;
int index = random.Next(alive.Length);
while (alive[index].Game.Referee || !alive[index].level.name.CaselessEq(CurLevelName)) {
while (alive[index].Game.Referee || !alive[index].level.name.CaselessEq(MapName)) {
if (index >= alive.Length - 1) {
index = 0;
alive = Alive.Items;
@ -96,7 +96,7 @@ namespace MCGalaxy.Games {
}
Player zombie = alive[index];
CurLevel.ChatLevel("&c" + zombie.DisplayName + " %Scontinued the infection!");
Map.ChatLevel("&c" + zombie.DisplayName + " %Scontinued the infection!");
InfectPlayer(zombie, null);
}
@ -141,20 +141,20 @@ namespace MCGalaxy.Games {
internal void ChangeLevel(string next) {
Player[] online = PlayerInfo.Online.Items;
if (CurLevel != null) {
Level.SaveSettings(CurLevel);
CurLevel.ChatLevel("The next map has been chosen - " + Colors.red + next.ToLower());
CurLevel.ChatLevel("Please wait while you are transfered.");
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 = CurLevelName;
string lastLevel = MapName;
CurLevelName = next;
QueuedLevel = null;
MapName = next;
Picker.QueuedMap = null;
CmdLoad.LoadLevel(null, next);
CurLevel = LevelInfo.FindExact(next);
CurLevel.SaveChanges = ZSConfig.ChangeLevels;
Map = LevelInfo.FindExact(next);
Map.SaveChanges = ZSConfig.ChangeLevels;
if (ZSConfig.SetMainLevel)
Server.mainLevel = CurLevel;
Server.mainLevel = Map;
online = PlayerInfo.Online.Items;
List<Player> players = new List<Player>(online.Length);
@ -198,7 +198,7 @@ namespace MCGalaxy.Games {
Infected.Clear();
Bounties.Clear();
RecentMaps.Clear();
Picker.RecentMaps.Clear();
foreach (Player pl in online) {
pl.Game.Referee = false;
@ -207,14 +207,13 @@ namespace MCGalaxy.Games {
ResetInvisibility(pl);
pl.SetPrefix();
if (pl.level == null || !pl.level.name.CaselessEq(CurLevelName))
continue;
if (pl.level == null || !pl.level.name.CaselessEq(MapName)) continue;
HUD.Reset(pl);
}
LastLevelName = "";
CurLevelName = "";
CurLevel = null;
MapName = "";
Map = null;
UnhookStats();
}

View File

@ -118,7 +118,7 @@ namespace MCGalaxy {
public bool ShouldShowJoinMessage(Level prev) {
ZSGame zs = Server.zombie;
if (zs.Running && name.CaselessEq(zs.CurLevelName) &&
if (zs.Running && name.CaselessEq(zs.MapName) &&
(prev == this || zs.LastLevelName.Length == 0 || prev.name.CaselessEq(zs.LastLevelName)))
return false;
if (Server.lava.active && Server.lava.HasMap(name))
@ -129,7 +129,7 @@ namespace MCGalaxy {
/// <summary> The currently active game running on this map,
/// or null if there is no game running. </summary>
public IGame CurrentGame() {
if (Server.zombie.Running && name.CaselessEq(Server.zombie.CurLevelName))
if (Server.zombie.Running && name.CaselessEq(Server.zombie.MapName))
return Server.zombie;
if (Server.lava.active && Server.lava.map == this)
return Server.lava;

View File

@ -503,6 +503,7 @@
<Compile Include="Games\LavaSurvival\LavaSurvival.Game.cs" />
<Compile Include="Games\LavaSurvival\LavaSurvival.cs" />
<Compile Include="Games\LavaSurvival\LavaSurvival.Settings.cs" />
<Compile Include="Games\LevelPicker.cs" />
<Compile Include="Games\MovementCheck.cs" />
<Compile Include="Games\Team.cs" />
<Compile Include="Games\Team.List.cs" />