Created
January 19, 2014 05:54
-
-
Save MrBluePotato/8500949 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright (c) <2013 - 2014> Michael Cummings <[email protected]> | |
// All rights reserved. | |
// | |
// Redistribution and use in source and binary forms, with or without | |
// modification, are permitted provided that the following conditions are met: | |
// * Redistributions of source code must retain the above copyright | |
// notice, this list of conditions and the following disclaimer. | |
// * Redistributions in binary form must reproduce the above copyright | |
// notice, this list of conditions and the following disclaimer in the | |
// documentation and/or other materials provided with the distribution. | |
// * Neither the name of AtomicCraft or the names of its | |
// contributors may be used to endorse or promote products derived from this | |
// software without specific prior written permission. | |
// | |
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY | |
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using JetBrains.Annotations; | |
using System.Threading; | |
namespace fCraft | |
{ | |
class PropHunt | |
{ | |
//Randoms | |
private static Random randBlock = new Random(); | |
public static Random randWorld = new Random(); | |
//Time stuff | |
private static SchedulerTask task_; | |
private DateTime startTime; | |
public static DateTime lastChecked; | |
public static DateTime roundEnd; | |
public static int timeLeft = 0; | |
public static int timeLimit = 300; | |
public static int timeDelay = 10; | |
//Bools | |
public static bool isOn = false; | |
public static bool VoteIsOn = false; | |
public static bool roundStarted = false; | |
//Stuff | |
public static PropHunt instance; | |
public static Game.StartMode startMode = ConfigKey.StartMode.GetEnum<Game.StartMode>(); | |
public static Thread VoteThread; | |
//Worlds and stufff | |
private static World _world; | |
private static World _winningWorld; | |
public static World world1; | |
public static World world2; | |
public static World world3; | |
//Lists | |
private static string[] blockId = { "1", "2", "4", "5", "7", "12", "13", "17", "19", "64", "65" }; | |
public static List<Player> PropHuntPlayers = new List<Player>(); | |
public static List<World> PropHuntWorlds = new List<World>(); | |
public static List<Player> Voted = new List<Player>(); | |
//Voting | |
public static int Voted1; | |
public static int Voted2; | |
public static int Voted3; | |
//For on-demand instances of PropHunt | |
public PropHunt(World world) | |
{ | |
_world = world; | |
startTime = DateTime.Now; | |
task_ = new SchedulerTask(Interval, true).RunForever(TimeSpan.FromMilliseconds(250)); | |
} | |
//Used if the server starts in prophunt | |
public PropHunt() | |
{ | |
lock (WorldManager.SyncRoot) | |
{ | |
foreach (World w in WorldManager.Worlds) | |
{ | |
if (w.IsPropHunt) | |
{ | |
PropHunt.PropHuntWorlds.Add(w); | |
} | |
} | |
} | |
if (PropHuntWorlds.Count() == 0) | |
{ | |
Server.Message("&cThere are no PropHunt maps set. Please add some with /PropHunt add [mapname]."); | |
return; | |
} | |
_world = PropHuntWorlds[randWorld.Next(0, PropHuntWorlds.Count)]; | |
startTime = DateTime.Now; | |
task_ = new SchedulerTask(Interval, true).RunForever(TimeSpan.FromMilliseconds(250)); | |
} | |
public void Start() | |
{ | |
#if !(DEBUG) | |
if (_world.Players.Count() < 4) //in case players leave the world or disconnect during the start delay | |
{ | |
_world.Players.Message("&WPropHunt&s requires at least 4 people to play."); | |
return; | |
} | |
#endif | |
_world.gameMode = GameMode.PropHunt; | |
startTime = DateTime.Now; | |
_world.Players.Message("&WPropHunt &S is starting in {0} seconds in world {1}", timeDelay, _world.ClassyName); | |
#if DEBUG | |
Server.Message("PropHunt is starting"); | |
#endif | |
} | |
public void Interval(SchedulerTask task) | |
{ | |
//check to stop Interval | |
if (_world == null) | |
{ | |
_world = null; | |
task.Stop(); | |
return; | |
#if DEBUG | |
Server.Message("World was null"); | |
#endif | |
} | |
if (_world.gameMode != GameMode.PropHunt) | |
{ | |
_world = null; | |
task.Stop(); | |
return; | |
#if DEBUG | |
Server.Message("Gamemode was not prophunt"); | |
#endif | |
} | |
if (!isOn) | |
{ | |
//Time delay if it is the on-demand instance of the game | |
if (startTime != null && (DateTime.Now - startTime).TotalSeconds > timeDelay && startMode != Game.StartMode.PropHunt) | |
{ | |
foreach (Player p in _world.Players) | |
{ | |
beginGame(p); | |
chooseSeeker(); | |
p.isPlayingPropHunt = true; | |
if (!p.isPropHuntSeeker) | |
{ | |
p.Model = blockId[randBlock.Next(0, blockId.Length)]; | |
} | |
} | |
} | |
//Handlers for various things | |
Player.Moving += PlayerMovingHandler; | |
Player.Clicking += PlayerClickingHandler; | |
Player.Connected += PlayerConnectedHandler; | |
checkIdlesTask = Scheduler.NewTask(CheckIdles).RunForever(CheckIdlesInterval); | |
isOn = true; | |
lastChecked = DateTime.Now; //used for intervals | |
#if DEBUG | |
Server.Message("It is on and stuff..."); | |
#endif | |
return; | |
} | |
timeLeft = Convert.ToInt16(((timeDelay + timeLimit) - (DateTime.Now - startTime).ToSeconds())); | |
if (_world.Players.Count(player => player.isPropHuntSeeker) == _world.Players.Count()) | |
{ | |
//Many things will happen here. | |
return; | |
} | |
if (_world.Players.Count(player => player.isPropHuntSeeker) == 0 && _world.Players.Count() > 0) | |
{ | |
//Lots of things will happen here. | |
return; | |
} | |
//Ondemand prophunt | |
if (timeLeft == 0 && startMode == Game.StartMode.None) | |
{ | |
Server.Message("the seeker couldnt get the nubs"); | |
return; | |
} | |
//Startup prophunt | |
if (timeLeft == 0 && startMode == Game.StartMode.PropHunt) | |
{ | |
Server.Message("The seeker couldnt do it"); | |
roundEnd = DateTime.Now; | |
if ((DateTime.Now - roundEnd).TotalSeconds >= 10) takeVote(); | |
roundStarted = false; | |
} | |
if (lastChecked != null && (DateTime.Now - lastChecked).TotalSeconds > 5 && timeLeft <= timeLimit) | |
{ | |
_world.Players.Message("There are currently {0} block(s) and {1} seeker(s) left on {2}", _world.Players.Count() - _world.Players.Count(player => !player.isPropHuntSeeker), _world.Players.Count(player => player.isPropHuntSeeker), _world.ClassyName); | |
lastChecked = DateTime.Now; | |
#if DEBUG | |
Server.Message("Announcement time!"); | |
#endif | |
} | |
} | |
public static void beginGame(Player player) | |
{ | |
player.isPlayingPropHunt = true; | |
PropHuntPlayers.Add(player); | |
Server.Message("&WPropHunt is starting!"); | |
roundStarted = true; | |
#if DEBUG | |
Server.Message("Beginning game...."); | |
#endif | |
} | |
// Choose a random player as the seeker | |
public static void chooseSeeker() | |
{ | |
Random randNumber = new Random(); | |
int randSeeker = randNumber.Next(0, _world.Players.Length); | |
Player seeker = _world.Players[randSeeker]; | |
if (_world.Players.Count(player => player.isPropHuntSeeker) == 0) | |
{ | |
seeker.Message("&cYou were chosen as the seeker!"); | |
seeker.isPropHuntSeeker = true; | |
} | |
} | |
//Called when the seeker tags a player (turns player into seeker) | |
public static void makeSeeker(Player p) | |
{ | |
p.isPropHuntTagged = false; | |
p.Message("&cYou were tagged! You are now a seeker!"); | |
p.Model = "steve"; | |
p.isPropHuntSeeker = true; | |
} | |
//Resets player and map settings from the game | |
public static void revertGame() | |
{ | |
lock (_world.Players) | |
{ | |
foreach (Player p in _world.Players) | |
{ | |
p.isPlayingPropHunt = false; | |
if (!p.isPropHuntSeeker) | |
{ | |
p.isSolidBlock = false; | |
p.Model = "steve"; | |
} | |
if (p.isPropHuntTagged) | |
{ | |
p.isPropHuntTagged = false; | |
} | |
p.isPropHuntSeeker = false; | |
} | |
} | |
isOn = false; | |
_world.gameMode = GameMode.NULL; | |
_world = null; | |
instance = null; | |
task_.Stop(); | |
} | |
//Voting | |
public static void NewVote() | |
{ | |
VoteIsOn = true; | |
} | |
public static void takeVote() | |
{ | |
VoteThread = new Thread(new ThreadStart(delegate | |
{ | |
NewVote(); | |
Server.Players.Message("&S--------------------------------------------------------------"); | |
Server.Players.Message("Vote for the next map!"); | |
Server.Players.Message("&S/Vote &c1&S for {0}&S, &c2&S for {1}&S, and &c3&S for {2}", world1.ClassyName, world2.ClassyName, world3.ClassyName); | |
Server.Players.Message("&S--------------------------------------------------------------"); | |
VoteIsOn = true; | |
Thread.Sleep(60000); | |
VoteCheck(); | |
})); VoteThread.Start(); | |
} | |
static void VoteCheck() | |
{ | |
if (VoteIsOn) | |
{ | |
if (Voted1 < Voted2 || Voted1 < Voted3) | |
{ | |
_winningWorld = world1; | |
return; | |
} | |
else if (Voted2 < Voted1 || Voted2 < Voted3) | |
{ | |
_winningWorld = world2; | |
return; | |
} | |
else if (Voted3 < Voted1 || Voted3 < Voted2) | |
{ | |
_winningWorld = world3; | |
return; | |
} | |
_world = _winningWorld; | |
Server.Players.Message("&S--------------------------------------------------------------"); | |
Server.Players.Message("&SVoting results are in! &A{0}&S:&C{1}, &A{2}&S:&C{3}, &A{4}&S:&C{5}", world1.ClassyName, | |
Voted1, world2.ClassyName, Voted2, world3.ClassyName, Voted3); | |
Server.Players.Message("&SThe next map is: {0}", _winningWorld.ClassyName); | |
Server.Players.Message("&S--------------------------------------------------------------"); | |
VoteIsOn = false; | |
foreach (Player V in Voted) | |
{ | |
V.HasVoted = false; | |
} | |
foreach (Player p in _world.Players) | |
{ | |
p.JoinWorld(_world, WorldChangeReason.Rejoin); | |
} | |
} | |
} | |
// Avoid re-defining the list every time your handler is called. Make it static! | |
static Block[] clickableBlocks = { | |
Block.Stone, Block.Grass, Block.Dirt, Block.Cobblestone, | |
Block.Plank, Block.Bedrock, Block.Sand, Block.Gravel, | |
Block.Log, Block.Sponge, Block.Crate, Block.StoneBrick }; | |
public static void PlayerClickingHandler(object sender, fCraft.Events.PlayerClickingEventArgs e) | |
{ | |
// if player clicked a non-air block | |
if (e.Action == ClickAction.Delete) | |
{ | |
Block currentBlock = e.Player.WorldMap.GetBlock(e.Coords); // Gets the blocks coords | |
// Check if currentBlock is on the list | |
if (clickableBlocks.Contains(currentBlock)) | |
{ | |
foreach (Player p in _world.Players) | |
{ | |
if (p.prophuntSolidPos == e.Coords && p.isSolidBlock) | |
{ | |
//Remove the players block | |
Block airBlock = Block.Air; | |
BlockUpdate blockUpdate = new BlockUpdate(null, p.prophuntSolidPos, airBlock); | |
p.World.Map.QueueUpdate(blockUpdate); | |
//Do the other stuff | |
p.Message("&cA seeker has found you! Run away!"); | |
p.isPropHuntTagged = true; | |
p.ResetIdleTimer(); | |
p.isSolidBlock = false; | |
p.Info.IsHidden = false; | |
Player.RaisePlayerHideChangedEvent(p); | |
} | |
} | |
e.Cancel = true; | |
} | |
} | |
} | |
// Checks if the seeker tagged a player, after they broke the block form | |
public static void PlayerMovingHandler(object sender, fCraft.Events.PlayerMovingEventArgs e) | |
{ | |
if (e.Player.isPropHuntSeeker) | |
{ | |
Vector3I oldPos = new Vector3I(e.OldPosition.X / 32, e.OldPosition.Y / 32, e.OldPosition.Z / 32); // Get the position of the player | |
Vector3I newPos = new Vector3I(e.NewPosition.X / 32, e.NewPosition.Y / 32, e.NewPosition.Z / 32); | |
if (oldPos.X != newPos.X || oldPos.Y != newPos.Y || oldPos.Z != newPos.Z) // Check if the positions are not the same (player moved) | |
{ | |
foreach (Player p in _world.Players) | |
{ | |
Vector3I pos = p.Position.ToBlockCoords(); // Converts to block coords | |
if (e.NewPosition.DistanceSquaredTo(pos.ToPlayerCoords()) <= 48 * 48) | |
{ | |
if (!p.isPropHuntSeeker && !p.isSolidBlock) | |
{ | |
makeSeeker(p); | |
} | |
} | |
} | |
} | |
} | |
} | |
//Used if the server starts prophunt on launch. This brings the player to the world that the game is in. | |
public static void PlayerConnectedHandler(object sender, fCraft.Events.PlayerConnectedEventArgs e) | |
{ | |
if (PropHunt.startMode == Game.StartMode.PropHunt && !e.Player.isPlayingPropHunt) | |
{ | |
e.StartingWorld = _world; | |
beginGame(e.Player); | |
e.Player.isPlayingPropHunt = true; | |
e.Player.Model = blockId[randBlock.Next(0, blockId.Length)]; | |
foreach (Player p in Server.Players) | |
{ | |
if (p.isPropHuntSeeker == true) | |
{ | |
break; | |
} | |
else | |
{ | |
if (Server.Players.Count() < 2) | |
{ | |
chooseSeeker(); | |
return; | |
} | |
else | |
{ | |
Server.Message("&cThere are not enough players online to being PropHunt. Please try again later."); | |
return; | |
} | |
} | |
} | |
if (roundStarted) | |
{ | |
e.Player.Message("You connected while a round was in progress. You have been made a seeker."); | |
e.Player.isPropHuntSeeker = true; | |
} | |
} | |
} | |
// checks for idle players | |
static SchedulerTask checkIdlesTask; | |
static TimeSpan checkIdlesInterval = TimeSpan.FromSeconds(1); | |
public static TimeSpan CheckIdlesInterval | |
{ | |
get { return checkIdlesInterval; } | |
set | |
{ | |
if (value.Ticks < 0) throw new ArgumentException("CheckIdlesInterval may not be negative."); | |
checkIdlesInterval = value; | |
if (checkIdlesTask != null) checkIdlesTask.Interval = checkIdlesInterval; | |
} | |
} | |
public static void CheckIdles(SchedulerTask task) | |
{ | |
Player[] tempPlayerList = _world.Players; | |
for (int i = 0; i < tempPlayerList.Length; i++) | |
{ | |
Player player = tempPlayerList[i]; | |
if (player.IdleTime.TotalSeconds < 7) continue; | |
if (player.IdleTime.TotalSeconds >= 7) | |
{ | |
if (!player.isSolidBlock && !player.isPropHuntSeeker) | |
{ | |
//Debug message to easily alert when player is idle | |
#if DEBUG | |
Server.Message("{0} is idle!", player.ClassyName); | |
#endif | |
player.Info.IsHidden = true; | |
player.isSolidBlock = true; | |
//Gets the coords of the player | |
short x = (short)(player.Position.X / 32 * 32 + 16); | |
short y = (short)(player.Position.Y / 32 * 32 + 16); | |
short z = (short)(player.Position.Z / 32 * 32); | |
Vector3I Pos = new Vector3I(player.Position.X / 32, player.Position.Y / 32, (player.Position.Z - 32) / 32); | |
//Saves the player pos when they were solid for later removing the block | |
player.prophuntSolidPos = Pos; | |
//Converts player's model block into Block.*blockname* | |
Block playerBlock = Map.GetBlockByName(player.Model); | |
//Places the block at the players current location | |
BlockUpdate blockUpdate = new BlockUpdate(null, Pos, playerBlock); | |
player.World.Map.QueueUpdate(blockUpdate); | |
player.WorldMap.SetBlock(Pos, playerBlock); | |
player.Message("&cYou are now a solid block. Don't move!"); | |
} | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment