public static void Control(PhysicsValues physicsValues, GameDuration elapsedDuration, Entity entity) { // initialize Behavior stores if necessary if (!_activeBehavior.ContainsKey(entity)) { Behavior defaultBehavior = InitializeBehaviors(entity); _activeBehavior.Add(entity, defaultBehavior); } Behavior current = _activeBehavior[entity]; // update the duration the active Behavior has been running current.AddToActiveDuration(elapsedDuration); // store all relevant data in BehaviorContext var context = new BehaviorContext(physicsValues, elapsedDuration); // if the minimum running duration of the current Behavior has passed, look for another applicable Behavior if (current.ActiveDuration > current.MinimumDuration()) { foreach (Behavior b in _possibleBehaviors[entity]) { // we only look for *other* Behaviors if (current.Equals(b)) { continue; } // determine the other Behavior's current priority var otherPrio = b.DeterminePriority(context); // only consider other Behavior if it's applicable if (otherPrio == BehaviorPriority.NA) { continue; } // switch to other Behavior depending on relation between priorities var currentPrio = current.DeterminePriority(context); if (otherPrio / (currentPrio + otherPrio) > Rng.NextDouble()) { // reset the current Behavior, as it might become active again later current.Reset(); // change active Behavior to new one _activeBehavior[entity] = b; current = b; ////Console.WriteLine("Entity {0} switched to behavior {1}", entity, b); } } } // let the active Behavior control the entity var position = entity.Get <PositionComponent>(); current.Behave(context, position); entity.Set(position); }
private void SetDefaults() { SetBoard(); StatusOfGame = GameStatus.DuringGame; GameTime = new GameDuration(); gameStarter = new GameStarter(this); }
public OptionsCategory OptionExecuting() { Timer = new GameDuration(); Timer.Start(); PlayingGame(); Timer.Stop(); DisplayResult(); var ProgramExecution = new DecisionOnFurtherCourseOfProgram(this); return(ProgramExecution.UserDecidesWhatToDoNext()); }
private void SetDefaults() { Timer = new GameDuration(); RandomPINnumbers = new int[4]; var random = new Random(); for (int i = 0; i < RandomPINnumbers.Length; ++i) { RandomPINnumbers[i] = random.Next(0, 10); } }
private void UpdateBuildAction(GameDuration elapsedDuration) { if (_placementCooldown > GameDuration.Zero) { _placementCooldown -= elapsedDuration; } var result = World.CastRay( PositionData.Placement.Pos + new EntityOffset(0, PhysicsValues.PlayerEyeHeight, 0), (EntityOffset)PositionData.Placement.Orientation, PhysicsValues.MiningDistance); if (result == null) { HighlightedBlock = null; _miningTime = GameDuration.Zero; } else { if (RayCastResult.FaceEquals(HighlightedBlock, result) && _controller.IsKeyPressed(GameKey.Primary)) { _miningTime += elapsedDuration; if (_miningTime.Seconds >= PhysicsValues.MiningTime) { _blockUpdates.Add(new BlockUpdateData { Pos = result.BlockPos, Material = 0, }); } } else { _miningTime = GameDuration.Zero; if (_placementCooldown <= GameDuration.Zero && _controller.IsKeyPressed(GameKey.Secondary)) { _placementCooldown.Seconds = PhysicsValues.PlacementCooldown; _blockUpdates.Add(new BlockUpdateData { Pos = result.BlockPos + result.Normal, Material = 1, }); } } HighlightedBlock = result; } }
private void MovePlayer(GameDuration elapsedDuration) { var velocity = new EntityOffset(0, PositionData.Velocity.Y, 0); var moveOffset = PhysicsValues.PlayerMovementSpeed * (EntityOffset) new EntityOrientation(PositionData.Placement.Orientation.Horizontal, 0); bool isMovingAlong = false, isMovingSideways = false; if (_controller.IsKeyPressed(GameKey.Forwards)) { isMovingAlong = true; velocity.X += moveOffset.X; velocity.Z += moveOffset.Z; } if (_controller.IsKeyPressed(GameKey.Left)) { isMovingSideways = true; velocity.X += moveOffset.Z; velocity.Z -= moveOffset.X; } if (_controller.IsKeyPressed(GameKey.Backwards)) { isMovingAlong = true; velocity.X -= moveOffset.X; velocity.Z -= moveOffset.Z; } if (_controller.IsKeyPressed(GameKey.Right)) { isMovingSideways = true; velocity.X -= moveOffset.Z; velocity.Z += moveOffset.X; } if (isMovingAlong && isMovingSideways) { velocity.X *= _inverseSqrt2; velocity.Z *= _inverseSqrt2; } if (!PositionData.IsFalling && _controller.IsKeyPressed(GameKey.Jump)) { velocity.Y += GetJumpingSpeed(); } Movement.MoveEntity(PhysicsValues, World, PositionData, elapsedDuration, velocity); }
public ImposterDrawingGameMode(Lobby lobby, List <ConfigureLobbyRequest.GameModeOptionRequest> gameModeOptions, StandardGameModeOptions standardOptions) { this.Lobby = lobby; TimeSpan? writingTimer = null; TimeSpan? drawingTimer = null; TimeSpan? votingTimer = null; GameDuration duration = standardOptions.GameDuration; if (standardOptions.TimerEnabled) { writingTimer = ImposterDrawingConstants.WritingTimer[duration]; drawingTimer = ImposterDrawingConstants.DrawingTimer[duration]; votingTimer = ImposterDrawingConstants.VotingTimer[duration]; } List <Prompt> prompts = new List <Prompt>(); int numRounds = Math.Min(ImposterDrawingConstants.MaxNumRounds[duration], this.Lobby.GetAllUsers().Count); int numDrawingsPerUser = Math.Min(ImposterDrawingConstants.MaxDrawingsPerPlayer[duration], numRounds - 1); numRounds = Math.Min(numRounds, (this.Lobby.GetAllUsers().Count - 1) * numDrawingsPerUser / ImposterDrawingConstants.MinNumPlayersPerRound); int playersPerPrompt = Math.Min(ImposterDrawingConstants.MaxNumPlayersPerRound, this.Lobby.GetAllUsers().Count - 1); playersPerPrompt = Math.Min(playersPerPrompt, this.Lobby.GetAllUsers().Count *numDrawingsPerUser / numRounds + 1); Setup = new Setup_GS( lobby: lobby, promptsToPopulate: prompts, writingTimeDuration: writingTimer, drawingTimeDuration: drawingTimer, numDrawingsPerUser: numDrawingsPerUser, numRounds: numRounds, maxPlayersPerPrompt: playersPerPrompt); StateChain CreateGamePlayLoop() { List <State> stateList = new List <State>(); foreach (Prompt prompt in prompts) { stateList.Add(GetImposterLoop(prompt, prompt == prompts.Last())); } StateChain gamePlayChain = new StateChain(states: stateList); gamePlayChain.Transition(this.Exit); return(gamePlayChain); } this.Entrance.Transition(Setup); Setup.Transition(CreateGamePlayLoop); StateChain GetImposterLoop(Prompt prompt, bool lastRound = false) { return(new StateChain( stateGenerator: (int counter) => { if (counter == 0) { return GetVotingAndRevealState(prompt, (prompt.UsersToDrawings.Values.Any(val => val == null)), votingTimer); } if (counter == 1) { if (lastRound) { return new ScoreBoardGameState(lobby, "Final Scores"); } else { return new ScoreBoardGameState(lobby); } } else { return null; } })); } }
public FriendQuizGameMode(Lobby lobby, List <ConfigureLobbyRequest.GameModeOptionRequest> gameModeOptions, StandardGameModeOptions standardOptions) { GameDuration duration = standardOptions.GameDuration; double questionPoolMultiplier = 2.5; // Question pool is X times bigger than number of questions per person. int numQuestionsToAnswer = (int)gameModeOptions[(int)GameModeOptionsEnum.NumAnswerQuestions].ValueParsed; int numRounds = Math.Min(lobby.GetAllUsers().Count(), FriendQuizConstants.MaxUserRounds[duration]); int numQuestionSetup = (int)(numQuestionsToAnswer * questionPoolMultiplier / numRounds) + 1; // How many questions each user should contribute. TimeSpan?setupTimer = null; TimeSpan?answeringTimer = null; TimeSpan?votingTimer = null; if (standardOptions.TimerEnabled) { setupTimer = FriendQuizConstants.SetupTimer[duration]; answeringTimer = FriendQuizConstants.AnsweringTimer[duration]; votingTimer = FriendQuizConstants.VotingTimer[duration]; } Dictionary <User, List <Question> > usersToAssignedQuestions = new Dictionary <User, List <Question> >(); int maxNumAssigned = 1; // Variable for tracking user with most questions. StateChain gameStateChain = new StateChain(stateGenerator: (int counter) => { if (counter == 0) { setupTimer = setupTimer?.Multiply(numQuestionSetup); return(new Setup_GS( lobby: lobby, roundTracker: RoundTracker, numExpectedPerUser: numQuestionSetup, setupDuration: setupTimer)); } else if (counter == 1) { List <UserQuestionsHolder> userQuestionsHolders = lobby.GetAllUsers().Select(user => new UserQuestionsHolder(user, numQuestionsToAnswer)).ToList(); List <Question> randomizedQuestions = RoundTracker.Questions.OrderBy(_ => Rand.Next()).ToList(); List <IGroup <Question> > assignments = MemberHelpers <Question> .Assign(userQuestionsHolders.Cast <IConstraints <Question> >().ToList(), randomizedQuestions, lobby.GetAllUsers().Count); var pairings = userQuestionsHolders.Zip(assignments); foreach ((UserQuestionsHolder holder, IGroup <Question> questions) in pairings) { if (questions.Members.Count() > maxNumAssigned) { maxNumAssigned = questions.Members.Count(); } // Makes a copy of the questions so that it can handle multiple people answering the same question without them both overriding the same object usersToAssignedQuestions.Add(holder.QuestionedUser, questions.Members.Select(question => new Question(question) { MainUser = holder.QuestionedUser }).ToList()); } answeringTimer = answeringTimer?.Multiply(maxNumAssigned); return(new AnswerQuestion_GS( lobby: lobby, usersToAssignedQuestions: usersToAssignedQuestions, answerTimeDuration: answeringTimer)); } else if (counter == 2) { votingTimer = votingTimer?.Multiply(maxNumAssigned); List <User> randomizedUsers = usersToAssignedQuestions.Keys .OrderBy(_ => Rand.Next()) .ToList() // Probably not needed, but just in case. .Take(numRounds) // Number of rounds is limited based on game duration. .ToList(); return(GetUserQueryStateChain(randomizedUsers)); } else { return(null); } }); this.Entrance.Transition(gameStateChain); gameStateChain.Transition(this.Exit); StateChain GetUserQueryStateChain(List <User> users) { List <State> chain = new List <State>(); foreach (User user in users) { List <Question> nonAbstainedQuestions = usersToAssignedQuestions[user].Where(question => !question.Abstained).ToList(); if (nonAbstainedQuestions.Count > 0) { chain.Add(new StateChain(stateGenerator: (int counter) => { if (counter == 0) { return(new SliderQueryAndReveal( lobby: lobby, objectsToQuery: nonAbstainedQuestions, usersToQuery: lobby.GetAllUsers().Where(lobbyUser => lobbyUser != user).ToList(), queryTime: votingTimer) { QueryPromptTitle = $"How do you think {user.DisplayName} answered these questions?", QueryPromptDescription = "The tighter the range of your guess, the more points if you're correct", QueryViewOverrides = new UnityViewOverrides() { Title = $"How do you think {user.DisplayName} answered these questions?", }, RevealViewOverrides = new UnityViewOverrides() { Title = $"This is how {user.DisplayName} answered those questions.", }, QueryExitListener = CountQueries, }); } else if (counter == 1) { if (user == users.Last()) { return(new ScoreBoardGameState(lobby, "Final Scores")); } else { return(new ScoreBoardGameState(lobby)); } } else { return(null); } })); } } return(new StateChain(chain)); } }
public BehaviorContext(PhysicsValues physicsValues, GameDuration elapsedDuration) { PhysicsValues = physicsValues; ElapsedDuration = elapsedDuration; }
public TwoToneDrawingGameMode(Lobby lobby, List <ConfigureLobbyRequest.GameModeOptionRequest> gameModeOptions, StandardGameModeOptions standardOptions) { this.Lobby = lobby; GameDuration duration = standardOptions.GameDuration; int maxPossibleTeamCount = 8; // Can go higher than this in extreme circumstances. bool useSingleColor = (bool)gameModeOptions[(int)GameModeOptionsEnum.useSingleColor].ValueParsed; int numLayers = (int)gameModeOptions[(int)GameModeOptionsEnum.numLayers].ValueParsed; int numPlayers = lobby.GetAllUsers().Count(); if (numLayers * 2 > numPlayers) { numLayers = numPlayers / 2; } int numRounds = Math.Min(TwoToneDrawingConstants.MaxNumRounds[duration], numPlayers); int numDrawingsPerPlayer = Math.Min(TwoToneDrawingConstants.DrawingsPerPlayer[duration], numRounds); int numTeamsLowerBound = Math.Max(2, 1 * numPlayers / (numRounds * numLayers)); // Lower bound. int numTeamsUpperBound = Math.Min(maxPossibleTeamCount, numDrawingsPerPlayer * numPlayers / (numRounds * numLayers)); // Upper bound. int numTeams = Math.Max(numTeamsLowerBound, numTeamsUpperBound); // Possible for lower bound to be higher than upper bound. that is okay. //int drawingsPerPlayer = numRounds * numLayers * numTeams / numPlayers; TimeSpan?setupTimer = null; TimeSpan?drawingTimer = null; TimeSpan?votingTimer = null; if (standardOptions.TimerEnabled) { setupTimer = TwoToneDrawingConstants.SetupTimer[duration]; drawingTimer = TwoToneDrawingConstants.PerDrawingTimer[duration].MultipliedBy(numDrawingsPerPlayer); votingTimer = TwoToneDrawingConstants.VotingTimer[duration]; } Setup = new Setup_GS( lobby: lobby, challengeTrackers: this.SubChallenges, useSingleColor: useSingleColor, numLayersPerTeam: numLayers, numTeamsPerPrompt: numTeams, numRounds: numRounds, setupTimer: setupTimer, drawingTimer: drawingTimer); StateChain GamePlayLoopGenerator() { List <ChallengeTracker> challenges = SubChallenges.Keys.OrderBy(_ => Rand.Next()).ToList(); StateChain chain = new StateChain( stateGenerator: (int counter) => { if (counter < challenges.Count) { return(new StateChain(stateGenerator: (int i) => { switch (i) { case 0: return GetVotingAndRevealState(challenges[counter], votingTimer); case 1: return ((counter == challenges.Count - 1) ? new ScoreBoardGameState(lobby, "Final Scores") : new ScoreBoardGameState(lobby)); default: return null; } })); } else { return(null); } }); chain.Transition(this.Exit); return(chain); } Setup.Transition(GamePlayLoopGenerator); this.Entrance.Transition(Setup); }
/// <summary> /// Adds the given duration to this Behavior's ActiveDuration. /// </summary> /// <param name="duration">The duration to add.</param> public void AddToActiveDuration(GameDuration duration) { _behaviorDuration += duration; }
/// <summary> /// Initializes a new instance of the <see cref="Behavior"/> class. /// </summary> /// <param name="entity">The entity controlled by this behavior.</param> public Behavior(Entity entity) { _entity = entity; _behaviorDuration = new GameDuration(0); }
public BehaviorContext(PhysicsValues physicsValues, GameDuration elapsedDuration, IEnumerable <Entity> otherEntities) { PhysicsValues = physicsValues; ElapsedDuration = elapsedDuration; OtherEntities = otherEntities; }
public static void MoveEntity(PhysicsValues physicsValues, World world, PositionData positionData, GameDuration elapsedDuration, EntityOffset offset) { offset.Y -= 0.5 * elapsedDuration.Seconds * physicsValues.Gravity; if (MoveY(physicsValues, world, positionData, offset.Y * elapsedDuration.Seconds)) { positionData.IsFalling = false; } else { if (!positionData.IsFalling) { /* Re-evaluate the fall from the apparent position. */ positionData.InternalPos = positionData.Placement.Pos; MoveY(physicsValues, world, positionData, offset.Y * elapsedDuration.Seconds); positionData.IsFalling = true; } } if (positionData.IsFalling) { offset.Y -= 0.5 * elapsedDuration.Seconds * physicsValues.Gravity; } else { if (Math.Abs(offset.Y) > Math.Sqrt(2 * physicsValues.Gravity * physicsValues.TerminalHeight)) { Respawn(positionData); } offset.Y = 0; } if (offset.X != 0 || offset.Z != 0) { long savedY = positionData.InternalPos.Y; if (!positionData.IsFalling && world[(BlockPos)positionData.InternalPos - BlockOffset.UnitY] != 0) { // Temporarily move the character up a block so that it can climb up stairs. MoveY(physicsValues, world, positionData, 1); } EntityPos positionBeforeMovement = positionData.InternalPos; double moveX = offset.X * elapsedDuration.Seconds; double moveZ = offset.Z * elapsedDuration.Seconds; if (offset.X > offset.Z) { MoveX(physicsValues, world, positionData, moveX); MoveZ(physicsValues, world, positionData, moveZ); } else { MoveZ(physicsValues, world, positionData, moveZ); MoveX(physicsValues, world, positionData, moveX); } var moveDelta = positionData.InternalPos - positionBeforeMovement; moveX -= moveDelta.X; moveZ -= moveDelta.Z; if (!positionData.IsFalling) { // Attempt to move the character back down to the ground in case we didn't climb a stair. MoveY(physicsValues, world, positionData, (savedY - positionData.InternalPos.Y) / (double)(1L << 32)); savedY = positionData.InternalPos.Y; // Attempt to move the caracter down an additional block so that it can walk down stairs. if (!MoveY(physicsValues, world, positionData, -((1L << 32) + 1) / (double)(1L << 32))) { positionData.InternalPos.Y = savedY; positionData.IsFalling = true; } } // Attempt to continue movement at this new (lower) Y position. if (offset.X > offset.Z) { if (MoveX(physicsValues, world, positionData, moveX)) { offset.X = 0; } if (MoveZ(physicsValues, world, positionData, moveZ)) { offset.Z = 0; } } else { if (MoveZ(physicsValues, world, positionData, moveZ)) { offset.Z = 0; } if (MoveX(physicsValues, world, positionData, moveX)) { offset.X = 0; } } } positionData.Velocity = offset; SetPositionFromCollisionPosition(physicsValues, world, positionData); }
public MimicGameMode(Lobby lobby, List <ConfigureLobbyRequest.GameModeOptionRequest> gameModeOptions, StandardGameModeOptions standardOptions) { GameDuration duration = standardOptions.GameDuration; int numStartingDrawingsPerUser = 1; int maxDrawingsBeforeVoteInput = (int)gameModeOptions[(int)GameModeOptions.MaxDrawingsBeforeVote].ValueParsed; int maxVoteDrawings = 12; // Everybody's drawing should show up, but it gets a little prohibitive past 12 so limit it here. TimeSpan? drawingTimer = null; TimeSpan? votingTimer = null; if (standardOptions.TimerEnabled) { drawingTimer = MimicConstants.DrawingTimer[duration]; votingTimer = MimicConstants.VotingTimer[duration]; } TimeSpan?extendedDrawingTimer = drawingTimer.MultipliedBy(MimicConstants.MimicTimerMultiplier); int numPlayers = lobby.GetAllUsers().Count(); int numRounds = Math.Min(MimicConstants.MaxRounds[duration], numPlayers); this.Lobby = lobby; Setup = new Setup_GS( lobby: lobby, drawings: Drawings, numDrawingsPerUser: numStartingDrawingsPerUser, drawingTimeDuration: drawingTimer); List <UserDrawing> randomizedDrawings = new List <UserDrawing>(); Setup.AddExitListener(() => { randomizedDrawings = this.Drawings .OrderBy(_ => Rand.Next()) .ToList() .Take(numRounds) // Limit number of rounds based on game duration. .ToList(); }); StateChain CreateGamePlayLoop() { bool timeToShowScores = true; StateChain gamePlayLoop = new StateChain(stateGenerator: (int counter) => { if (randomizedDrawings.Count > 0) { StateChain CreateMultiRoundLoop() { int maxDrawingsBeforeVote = Math.Min(maxDrawingsBeforeVoteInput, randomizedDrawings.Count); if (randomizedDrawings.Count == 0) { throw new Exception("Something went wrong while setting up the game"); } List <RoundTracker> roundTrackers = new List <RoundTracker>(); return(new StateChain(stateGenerator: (int counter) => { if (counter < maxDrawingsBeforeVote) { UserDrawing originalDrawing = randomizedDrawings.First(); randomizedDrawings.RemoveAt(0); RoundTracker drawingsRoundTracker = new RoundTracker(); roundTrackers.Add(drawingsRoundTracker); drawingsRoundTracker.originalDrawer = originalDrawing.Owner; drawingsRoundTracker.UsersToUserDrawings.AddOrUpdate(originalDrawing.Owner, originalDrawing, (User user, UserDrawing drawing) => originalDrawing); DisplayOriginal_GS displayGS = new DisplayOriginal_GS( lobby: lobby, displayTimeDuration: MimicConstants.MemorizeTimerLength, displayDrawing: originalDrawing); CreateMimics_GS mimicsGS = new CreateMimics_GS( lobby: lobby, roundTracker: drawingsRoundTracker, drawingTimeDuration: extendedDrawingTimer ); mimicsGS.AddExitListener(() => { List <User> randomizedUsersToDisplay = new List <User>(); List <User> randomizedKeys = drawingsRoundTracker.UsersToUserDrawings.Keys.OrderBy(_ => Rand.Next()).ToList(); for (int i = 0; i < maxVoteDrawings && i < randomizedKeys.Count; i++) { randomizedUsersToDisplay.Add(randomizedKeys[i]); } if (!randomizedUsersToDisplay.Contains(drawingsRoundTracker.originalDrawer)) { randomizedUsersToDisplay.RemoveAt(0); randomizedUsersToDisplay.Add(drawingsRoundTracker.originalDrawer); } randomizedUsersToDisplay = randomizedUsersToDisplay.OrderBy(_ => Rand.Next()).ToList(); drawingsRoundTracker.UsersToDisplay = randomizedUsersToDisplay; }); return new StateChain(states: new List <State>() { displayGS, mimicsGS }, exit: null); } else if (counter < maxDrawingsBeforeVote * 2) { return GetVotingAndRevealState(roundTrackers[counter - maxDrawingsBeforeVote], votingTimer); } else { return null; } })); } return(CreateMultiRoundLoop()); } else { if (timeToShowScores) { timeToShowScores = false; return(new ScoreBoardGameState( lobby: lobby, title: "Final Scores")); } else { //Ends the chain return(null); } } }); gamePlayLoop.Transition(this.Exit); return(gamePlayLoop); } this.Entrance.Transition(Setup); Setup.Transition(CreateGamePlayLoop); }
public HardCodedGameFactory(IOptions <GameDuration> options) { _options = options.Value; }
/// <summary> /// Resets this Behavior. /// </summary> public void Reset() { _behaviorDuration = new GameDuration(0); }
public BattleReadyGameMode(Lobby lobby, List <ConfigureLobbyRequest.GameModeOptionRequest> gameModeOptions, StandardGameModeOptions standardOptions) { GameDuration duration = standardOptions.GameDuration; this.Lobby = lobby; int numRounds = BattleReadyConstants.NumRounds[duration]; int numPlayers = lobby.GetAllUsers().Count(); TimeSpan?setupDrawingTimer = null; TimeSpan?setupPromptTimer = null; TimeSpan?creationTimer = null; TimeSpan?votingTimer = null; int numOfEachPartInHand = (int)gameModeOptions[(int)GameModeOptionsEnum.NumEachPartInHand].ValueParsed; int numPromptsPerRound = Math.Min(numPlayers, BattleReadyConstants.MaxNumSubRounds[duration]); int minDrawingsRequired = numOfEachPartInHand * 3; // the amount to make one playerHand to give everyone int expectedPromptsPerUser = (int)Math.Ceiling(1.0 * numPromptsPerRound * numRounds / lobby.GetAllUsers().Count); int expectedDrawingsPerUser = Math.Max((minDrawingsRequired / numPlayers + 1) * 2, BattleReadyConstants.NumDrawingsPerPlayer[duration]); if (standardOptions.TimerEnabled) { setupDrawingTimer = BattleReadyConstants.SetupPerDrawingTimer[duration]; setupPromptTimer = BattleReadyConstants.SetupPerPromptTimer[duration]; creationTimer = BattleReadyConstants.PerCreationTimer[duration]; votingTimer = BattleReadyConstants.VotingTimer[duration]; } SetupDrawings_GS setupDrawing = new SetupDrawings_GS( lobby: lobby, drawings: this.Drawings, numExpectedPerUser: expectedDrawingsPerUser, setupDurration: setupDrawingTimer * expectedDrawingsPerUser); SetupPrompts_GS setupPrompt = new SetupPrompts_GS( lobby: lobby, prompts: Prompts, numExpectedPerUser: expectedPromptsPerUser, setupDuration: setupPromptTimer); List <Prompt> battlePrompts = new List <Prompt>(); IReadOnlyList <PeopleUserDrawing> headDrawings = new List <PeopleUserDrawing>(); IReadOnlyList <PeopleUserDrawing> bodyDrawings = new List <PeopleUserDrawing>(); IReadOnlyList <PeopleUserDrawing> legsDrawings = new List <PeopleUserDrawing>(); setupDrawing.AddExitListener(() => { // Trim extra prompts/drawings. headDrawings = Drawings.ToList().FindAll((drawing) => drawing.Type == BodyPartType.Head); bodyDrawings = Drawings.ToList().FindAll((drawing) => drawing.Type == BodyPartType.Body); legsDrawings = Drawings.ToList().FindAll((drawing) => drawing.Type == BodyPartType.Legs); }); int numPromptsPerUserPerRound = 0; // Set during below exit listener. setupPrompt.AddExitListener(() => { battlePrompts = MemberHelpers <Prompt> .Select_Ordered(Prompts.OrderBy(prompt => prompt.CreationTime).ToList(), numPromptsPerRound * numRounds); numRounds = (battlePrompts.Count - 1) / numPromptsPerRound + 1; numPromptsPerRound = (int)Math.Ceiling(1.0 * battlePrompts.Count / numRounds); numPromptsPerUserPerRound = Math.Max(1, numPromptsPerRound / 2); int maxNumUsersPerPrompt = Math.Min(12, (int)Math.Ceiling(1.0 * numPlayers * numPromptsPerUserPerRound / numPromptsPerRound)); foreach (Prompt prompt in battlePrompts) { prompt.MaxMemberCount = maxNumUsersPerPrompt; } }); List <GameState> creationGameStates = new List <GameState>(); List <GameState> votingGameStates = new List <GameState>(); List <GameState> voteRevealedGameStates = new List <GameState>(); List <GameState> scoreboardGameStates = new List <GameState>(); int countRounds = 0; #region GameState Generators GameState CreateContestantCreationGamestate() { RoundTracker.ResetRoundVariables(); List <Prompt> prompts = battlePrompts.Take(numPromptsPerRound).ToList(); battlePrompts.RemoveRange(0, prompts.Count); List <IGroup <User> > assignments = MemberHelpers <User> .Assign( prompts.Cast <IConstraints <User> >().ToList(), lobby.GetAllUsers().ToList(), duplicateMembers : (int)Math.Ceiling((1.0 * prompts.Count / numPromptsPerRound) * numPromptsPerUserPerRound)); var pairings = prompts.Zip(assignments); foreach ((Prompt prompt, IGroup <User> users) in pairings) { foreach (User user in users.Members) { prompt.UsersToUserHands.TryAdd(user, new Prompt.UserHand { // Users have even probabilities regardless of how many drawings they submitted. HeadChoices = MemberHelpers <PeopleUserDrawing> .Select_DynamicWeightedRandom(headDrawings, numOfEachPartInHand), BodyChoices = MemberHelpers <PeopleUserDrawing> .Select_DynamicWeightedRandom(bodyDrawings, numOfEachPartInHand), LegChoices = MemberHelpers <PeopleUserDrawing> .Select_DynamicWeightedRandom(legsDrawings, numOfEachPartInHand), Owner = user }); if (!RoundTracker.UsersToAssignedPrompts.ContainsKey(user)) { RoundTracker.UsersToAssignedPrompts.Add(user, new List <Prompt>()); } RoundTracker.UsersToAssignedPrompts[user].Add(prompt); } } GameState toReturn = new ContestantCreation_GS( lobby: lobby, roundTracker: RoundTracker, creationDuration: creationTimer); toReturn.Transition(CreateVotingGameStates(prompts)); return(toReturn); } Func <StateChain> CreateVotingGameStates(List <Prompt> roundPrompts) { return(() => { StateChain voting = new StateChain( stateGenerator: (int counter) => { if (counter < roundPrompts.Count) { Prompt roundPrompt = roundPrompts[counter]; return GetVotingAndRevealState(roundPrompt, votingTimer); } else { // Stops the chain. return null; } }); voting.Transition(CreateScoreGameState(roundPrompts)); return voting; }); } Func <GameState> CreateScoreGameState(List <Prompt> roundPrompts) { return(() => { List <Person> winnersPeople = roundPrompts.Select((prompt) => (Person)prompt.UsersToUserHands[prompt.Winner]).ToList(); countRounds++; GameState displayPeople = new DisplayPeople_GS( lobby: lobby, title: "Here are your winners", peopleList: winnersPeople, imageTitle: (person) => roundPrompts[winnersPeople.IndexOf(person)].Text, imageHeader: (person) => person.Name ); if (battlePrompts.Count <= 0) { GameState finalScoreBoard = new ScoreBoardGameState( lobby: lobby, title: "Final Scores"); displayPeople.Transition(finalScoreBoard); finalScoreBoard.Transition(this.Exit); } else { GameState scoreBoard = new ScoreBoardGameState( lobby: lobby); displayPeople.Transition(scoreBoard); scoreBoard.Transition(CreateContestantCreationGamestate); } return displayPeople; }); } #endregion this.Entrance.Transition(setupDrawing); setupDrawing.Transition(setupPrompt); setupPrompt.Transition(CreateContestantCreationGamestate); }