public bool FindPath(TalentNode node, IEnumerable <TalentNode> characterTalents, IList <TalentNode> procesedNodes) { procesedNodes.Add(node); var(x, y) = TalentPositionHelper.GetCoordinatesFromPosition(node.Position); if ((Math.Abs(x - _centerX) == 1 && y == _centerY) || (Math.Abs(y - _centerY) == 1 && x == _centerX)) { return(true); } var leftTalent = characterTalents.FirstOrDefault(k => { var coordinates = TalentPositionHelper.GetCoordinatesFromPosition(k.Position); return(coordinates.x == x + 1 && coordinates.y == y); }); if (leftTalent != null && !procesedNodes.Contains(leftTalent) && FindPath(leftTalent, characterTalents, procesedNodes)) { return(true); } var rightTalent = characterTalents.FirstOrDefault(k => { var coordinates = TalentPositionHelper.GetCoordinatesFromPosition(k.Position); return(coordinates.x == x - 1 && coordinates.y == y); }); if (rightTalent != null && !procesedNodes.Contains(rightTalent) && FindPath(rightTalent, characterTalents, procesedNodes)) { return(true); } var topTalent = characterTalents.FirstOrDefault(k => { var coordinates = TalentPositionHelper.GetCoordinatesFromPosition(k.Position); return(coordinates.x == x && coordinates.y == y - 1); }); if (topTalent != null && !procesedNodes.Contains(topTalent) && FindPath(topTalent, characterTalents, procesedNodes)) { return(true); } var bottomTalent = characterTalents.FirstOrDefault(k => { var coordinates = TalentPositionHelper.GetCoordinatesFromPosition(k.Position); return(coordinates.x == x && coordinates.y == y + 1); }); if (bottomTalent != null && !procesedNodes.Contains(bottomTalent) && FindPath(bottomTalent, characterTalents, procesedNodes)) { return(true); } return(false); }
public async Task <ActiveUserDto> Handle(GetActiveUserQuery request, CancellationToken cancellationToken) { var user = await _userManager.GetUserAsync(request.User); var statusInBattle = _battleService.IsUserInBattle(user.Id); var roster = await _gameContext.Rosters.GetOneAsync(x => x.UserId == user.Id); IEnumerable <Character> characters; if (roster == null) { roster = new Roster() { Id = user.Id, UserId = user.Id, Experience = 0, Seed = user.Id.GetHashCode(), TavernCapacity = 6, BoughtPatrons = new int[0] }; _gameContext.Rosters.InsertOne(roster); var userCharacter = new Character() { Id = Guid.NewGuid().ToString(), Deleted = false, IsKeyCharacter = true, RosterId = roster.Id, Name = user.ViewName, ChosenTalents = new int[0] }; _gameContext.Characters.InsertOne(userCharacter); characters = new Character[] { userCharacter }; await _gameContext.ApplyChangesAsync(); } else { characters = await _gameContext.Characters.GetAsync(x => x.RosterId == roster.Id && !x.Deleted); } var tavern = new List <CharacterForSaleDto>(); for (int i = 1; i <= roster.TavernCapacity; i++) { if (!roster.BoughtPatrons.Any(x => x == i)) { tavern.Add(new CharacterForSaleDto() { Id = i }); } } var talents = await _registryContext.TalentMap.GetAsync(x => true); return(new ActiveUserDto() { Name = user.ViewName, UniqueId = user.UserName, Id = user.Id, Email = user.Email, State = statusInBattle ? UserState.Battle : UserState.Lobby, Experience = roster.Experience, Tavern = tavern, Roster = characters.Select(x => { return new CharacterDto() { Id = x.Id, Name = x.Name, IsKeyCharacter = x.IsKeyCharacter, Talents = x.ChosenTalents.Select(k => { var coordinates = TalentPositionHelper.GetCoordinatesFromPosition(k); return new PointDto() { X = coordinates.x, Y = coordinates.y }; }) }; }), TalentsMap = talents.Select(x => { var position = TalentPositionHelper.GetCoordinatesFromPosition(x.Position); return new TalentNodeDto() { X = position.x, Y = position.y, Name = x.Name, Description = x.UniqueDescription, Id = x.Id, Speed = x.SpeedModifier, Strength = x.StrengthModifier, Willpower = x.WillpowerModifier, Constitution = x.ConstitutionModifier, Class = x.Class, ClassPoints = x.ClassPoints, Prerequisites = x.Prerequisites, Exceptions = x.Exceptions, SkillsAmount = x.SkillsAmount }; }) }); }
public async Task <Unit> Handle(ChangeCharacterTalentsCommand request, CancellationToken cancellationToken) { var roster = await _gameContext.Rosters.GetOneAsync(x => x.UserId == request.UserId); if (roster == null) { throw new NotFoundException("User is not found"); } var character = await _gameContext.Characters.GetOneAsync(x => x.Id == request.CharacterId); if (character == null) { throw new NotFoundException("Character is not found"); } if (character.RosterId != roster.Id) { throw new CannotPerformOperationException("Character is not belong to user"); } var changedTalentPositions = request.Changes.Select(x => TalentPositionHelper.GetPositionFromCoordinates(x.X, x.Y)).ToList(); var allTalentPositions = character.ChosenTalents.Union(changedTalentPositions).Distinct().ToList(); var allTalents = await _registryContext.TalentMap.GetAsync(x => allTalentPositions.Contains(x.Position)); var characterTalents = allTalents.Where(x => character.ChosenTalents.Contains(x.Position)).ToList(); var strength = BattleHelper.DefaultStrength; var willpower = BattleHelper.DefaultWillpower; var constitution = BattleHelper.DefaultConstitution; var speed = BattleHelper.DefaultSpeed; var skillsCount = 1; var cost = 0; var talentsCount = 0; characterTalents.ForEach(x => { strength += x.StrengthModifier; willpower += x.WillpowerModifier; constitution += x.ConstitutionModifier; speed += x.SpeedModifier; skillsCount += x.SkillsAmount; talentsCount++; }); var newTalents = new List <TalentNodeChangeDeclarationDto>(); foreach (var change in request.Changes) { var changePosition = TalentPositionHelper.GetPositionFromCoordinates(change.X, change.Y); // Accessibility check TalentNodeChangeDeclarationDto talent; if ((talent = newTalents.FirstOrDefault(x => x.X == change.X && x.Y == change.Y)) != null) { if (change.State == talent.State) { throw new CannotPerformOperationException("Cannot do the same action with talent twice"); } cost--; newTalents.Remove(talent); } else { if (characterTalents.Any(x => x.Position == changePosition) == change.State) { throw new CannotPerformOperationException("Cannot do action with talent"); } cost++; newTalents.Add(change); } var changeTalent = allTalents.First(x => x.Position == changePosition); // ConditionalsCheck if (change.State) { if (!((Math.Abs(change.X - _centerX) == 1 && change.Y == _centerY) || (Math.Abs(change.Y - _centerY) == 1 && change.X == _centerX)) && !characterTalents.Any(x => { var talentCoordinates = TalentPositionHelper.GetCoordinatesFromPosition(x.Position); return((Math.Abs(change.X - talentCoordinates.x) == 1 && change.Y == talentCoordinates.y) || (Math.Abs(change.Y - talentCoordinates.y) == 1 && change.X == talentCoordinates.x)); })) { throw new CannotPerformOperationException("Cannot pick remote talent"); } if (changeTalent.Exceptions != null && characterTalents.Any(x => changeTalent.Exceptions.Contains(x.Id))) { throw new CannotPerformOperationException("Cannot add talent with unprocessible exceptions"); } if (changeTalent.Prerequisites != null && changeTalent.Prerequisites.Any(x => !characterTalents.Any(t => t.Id == x))) { throw new CannotPerformOperationException("Cannot add talent with unresolved prerequisites"); } talentsCount++; strength += changeTalent.StrengthModifier; willpower += changeTalent.WillpowerModifier; constitution += changeTalent.ConstitutionModifier; speed += changeTalent.SpeedModifier; skillsCount += changeTalent.SkillsAmount; characterTalents.Add(changeTalent); } else { talentsCount--; strength -= changeTalent.StrengthModifier; willpower -= changeTalent.WillpowerModifier; constitution -= changeTalent.ConstitutionModifier; speed -= changeTalent.SpeedModifier; skillsCount -= changeTalent.SkillsAmount; characterTalents.Remove(characterTalents.First(x => x.Position == changePosition)); var leftTalent = characterTalents.FirstOrDefault(x => { var coordinates = TalentPositionHelper.GetCoordinatesFromPosition(x.Position); return(coordinates.x == change.X + 1 && coordinates.y == change.Y); }); var rightTalent = characterTalents.FirstOrDefault(x => { var coordinates = TalentPositionHelper.GetCoordinatesFromPosition(x.Position); return(coordinates.x == change.X - 1 && coordinates.y == change.Y); }); var topTalent = characterTalents.FirstOrDefault(x => { var coordinates = TalentPositionHelper.GetCoordinatesFromPosition(x.Position); return(coordinates.x == change.X && coordinates.y == change.Y - 1); }); var bottomTalent = characterTalents.FirstOrDefault(x => { var coordinates = TalentPositionHelper.GetCoordinatesFromPosition(x.Position); return(coordinates.x == change.X && coordinates.y == change.Y + 1); }); if ((leftTalent != null && !FindPath(leftTalent, characterTalents, new List <TalentNode>())) || (rightTalent != null && !FindPath(rightTalent, characterTalents, new List <TalentNode>())) || (topTalent != null && !FindPath(topTalent, characterTalents, new List <TalentNode>())) || (bottomTalent != null && !FindPath(bottomTalent, characterTalents, new List <TalentNode>()))) { throw new CannotPerformOperationException("Remains talents without bonds"); } } if (talentsCount > _talentsMaxCount) { throw new CannotPerformOperationException("Extra talents"); } if (cost > roster.Experience) { throw new CannotPerformOperationException("Not enough money"); } if (strength < 5 || willpower < 5 || constitution < 5 || speed < 5) { throw new CannotPerformOperationException("Stats cannot be less than five"); } if (skillsCount > 5) { throw new CannotPerformOperationException("Skills amount cannot be more than 5"); } } foreach (var change in newTalents) { if (change.State) { _gameContext.Characters.Update( x => x.Id == character.Id, Builders <Character> .Update.Push(k => k.ChosenTalents, TalentPositionHelper.GetPositionFromCoordinates(change.X, change.Y))); } else { _gameContext.Characters.Update( x => x.Id == character.Id, Builders <Character> .Update.Pull(k => k.ChosenTalents, TalentPositionHelper.GetPositionFromCoordinates(change.X, change.Y))); } } _gameContext.Rosters.Update( x => x.UserId == roster.UserId, Builders <Roster> .Update.Set(k => k.Experience, roster.Experience - cost)); await _gameContext.ApplyChangesAsync(); return(Unit.Value); }