/// <summary> /// Usually the current JPS implementation creates too many jump points (many of them are aligned in one line). /// This function gives three first „natural” jump points (two or three), which means they don't form a single line. /// </summary> public IList <Vector2Int> GetNaturalJumpPoints(IList <Vector2Int> jumpPoints) { if (jumpPoints.Count <= 2) { return(jumpPoints); } var result = new List <Vector2Int> { jumpPoints[0] }; Vector2Int currentDirectionNormalized = Vector2IntUtilities.Normalized(jumpPoints[1] - jumpPoints[0]); for (int i = 2; i < jumpPoints.Count; i++) // we should start checking from current == third and previous == second { Vector2Int previousPointToCheck = jumpPoints[i - 1]; Vector2Int currentPointToCheck = jumpPoints[i]; Vector2Int currentDirection = Vector2IntUtilities.Normalized(currentPointToCheck - previousPointToCheck); if (currentDirection != currentDirectionNormalized) // change of direction implicates that the last jump point was natural { result.Add(previousPointToCheck); currentDirectionNormalized = currentDirection; } } result.Add(jumpPoints.Last()); return(result); }
public void Pawel() { foreach (var direction in Vector2IntUtilities.Neighbours8(Vector2Int.zero)) { Console.WriteLine(direction + ", " + ZRotationForLookAt2D(direction.x, direction.y)); } }
public void DwaDalej() { var position = new Vector2Int(3, 10); foreach (var vector2Int in Vector2IntUtilities.Neighbours8(Vector2Int.zero) .Select(v => new Vector2Int(v.x * 2, v.y * 2)) .Select(v => position + v)) { Console.WriteLine(vector2Int); } }
public void Cofanie() { var actorPosition = new Vector2Int(10, 10); var toEnemy = new Vector2Int(-1, -1); Vector2Int directionFromEnemy = Vector2IntUtilities.Normalized(toEnemy) * -1; IEnumerable <Vector2Int> positionsToStepBack = Vector2IntUtilities.GetCone(directionFromEnemy) .Select(coneVector => actorPosition + coneVector - directionFromEnemy); foreach (var vector2Int in positionsToStepBack) { Console.WriteLine(vector2Int); } }
public static BoundsInt GetFurthestRoomToStairs(Dungeon currentDungeon) { var roomsSortedByDistanceToStairs = currentDungeon.Rooms.ToList(); roomsSortedByDistanceToStairs.Sort( (first, second) => Vector2IntUtilities.WalkDistance(currentDungeon.StairsLocation, first.min.ToVector2Int()) .CompareTo( Vector2IntUtilities.WalkDistance(currentDungeon.StairsLocation, second.min.ToVector2Int())) ); BoundsInt furthestRoomToStairs = roomsSortedByDistanceToStairs.Last(); return(furthestRoomToStairs); }
private int GetEmptyPositionsAround(ActorData actorData) { int emptyPositions = 8; var positionsAround = Vector2IntUtilities.Neighbours8(actorData.LogicalPosition); foreach (Vector2Int position in positionsAround) { if (!_gridInfoProvider.IsWalkable(position) || _entityDetector.DetectActors(position).Any()) { --emptyPositions; } } return(emptyPositions); }
/// <summary> /// Returns normalized vectors that point from a tile to the tile that can be considered to be "behind" it. /// </summary> internal IEnumerable <Vector2Int> GetBehindnessVectors(Vector2Int currentPosition, Vector2Int centerOfSquareToPostProcess) { Vector2Int direction = currentPosition - centerOfSquareToPostProcess; var snappedToX = Vector2IntUtilities.SnapToXAxisNormalized(direction); var snappedToY = Vector2IntUtilities.SnapToYAxisNormalized(direction); if (snappedToX != Vector2Int.zero) { yield return(snappedToX); } if (snappedToY != Vector2Int.zero) { yield return(snappedToY); } }
private Vector2Int GetPositionToPlaceActor(Vector2Int position) { List <Vector2Int> candidates = Vector2IntUtilities.Neighbours8(position); var candidatesFurther = Vector2IntUtilities.Neighbours8(Vector2Int.zero) .Select(v => new Vector2Int(v.x * 2, v.y * 2)) .Select(v => position + v); candidates.AddRange(candidatesFurther); foreach (Vector2Int neighbour in candidates) { if (_gridInfoProvider.IsWalkable(neighbour) && !_entityDetector.DetectActors(neighbour).Any()) { return(neighbour); } } return(position); }
public override IEnumerable <IActionEffect> Execute() { float chanceToSucceed = ActorData.Accuracy; bool success = _rng.Check(chanceToSucceed); yield return(new BumpEffect(ActorData, _targetEnemy.LogicalPosition)); if (success) { _targetEnemy.Energy -= 1.2f; --ActorData.Swords; Vector2Int direction = _targetEnemy.LogicalPosition - ActorData.LogicalPosition; Assert.IsTrue(Vector2IntUtilities.IsOneStep(direction)); Vector2Int previousPosition = _targetEnemy.LogicalPosition; _targetEnemy.LogicalPosition += direction; yield return(new MoveEffect(_targetEnemy, previousPosition, _gridInfoProvider, _entityDetector, _uiConfig)); } }
private Vector2Int?GetFarReachablePoint(ActorData actorData) { var reachableRandomPoints = new List <Vector2Int>(); for (int i = 0; i < 5; i++) { Vector2Int wanderVector = new Vector2Int(_rng.Next(-7, 7), _rng.Next(-7, 7)); Vector2Int candidate = actorData.LogicalPosition + wanderVector; if (_clearWayBetweenTwoPointsDetector.ClearWayExists(actorData.LogicalPosition, candidate)) { reachableRandomPoints.Add(candidate); } } if (reachableRandomPoints.Any()) { reachableRandomPoints.Sort((first, second) => Vector2IntUtilities.WalkDistance(actorData.LogicalPosition, first).CompareTo(Vector2IntUtilities.WalkDistance(actorData.LogicalPosition, second)) ); return(reachableRandomPoints.First()); } return(null); }
public override IEnumerable <IActionEffect> Execute() { Vector2Int previousPosition = ActorData.LogicalPosition; Vector2Int newPosition = previousPosition + Direction; if (_gridInfoProvider.IsWalkable(newPosition)) { if (ActorData.ActorType == ActorType.Player && _gameContext.EnvironmentTilemap.HasTile(newPosition.ToVector3Int())) { TileBase stairsDownTile = Resources.Load <TileBase>("Tiles/Environment/Stairs_down"); if (_gameContext.EnvironmentTilemap.GetTile(newPosition.ToVector3Int()) == stairsDownTile) { _textEffectPresenter.ShowTextEffect(ActorData.LogicalPosition, "Back down? Never!", Color.yellow); } } if (_gameContext.BasherSteps == 0 && ActorData.ActorType == ActorType.Basher && Vector2IntUtilities.WalkDistance(ActorData.LogicalPosition, _gameContext.PlayerActor.ActorData.LogicalPosition) <= 5) { _gameContext.BasherSteps = 1; _uiConfig.BasherMessage.gameObject.SetActive(true); _uiConfig.BasherMessage.SetMessage("Ha! So you didn't disappoint me! Finally I see you again, my rattish friend! As you might " + "have guessed, that was me that sent you the key. I'll be happy to take you away from this scary place. But first " + "we have to deal with one thing. You saved my life by attributing to yourself my deeds against the revolutionists. " + "But this also made me feel like a lousy coward. My honour has been terribly undermined and I need to clean it. " + "I challenge you to a duel! No magic, no eating, just me, you and steel. Prepare!"); IEnumerable <ActorData> friendsAndBuddies = _entityDetector.DetectActors(ActorData.LogicalPosition, 15) .Where(a => a.ActorType == ActorType.Friend || a.ActorType == ActorType.Buddy); foreach (var friendOrBuddy in friendsAndBuddies) { _deathHandler.HandleDeath(friendOrBuddy); } } IActionEffect effect = ActionEffectFactory.CreateMoveEffect(ActorData, previousPosition); ActorData.LogicalPosition = newPosition; if (ActorData.CaughtActor != null) { ActorData.CaughtActor.LogicalPosition = newPosition; } yield return(effect); } else { IActionEffect effect = ActionEffectFactory.CreateBumpEffect(ActorData, newPosition); yield return(effect); } }
public virtual void Process() { bool visibleEnemiesClose = ActorData.ControlledByPlayer && _entityDetector.DetectActors(ActorData.LogicalPosition, 3) .Count(a => a.Team != Team.Beasts && a.Entity.IsVisible) > 0; if (visibleEnemiesClose) { DateTime potentialBlockedUntil = DateTime.UtcNow + TimeSpan.FromMilliseconds(150); ActorData.BlockedUntil = potentialBlockedUntil > ActorData.BlockedUntil ? potentialBlockedUntil : ActorData.BlockedUntil; } IGameEntity entity = ActorData.Entity; IEntityAnimator entityAnimator = entity.EntityAnimator; IEnumerable <ActorData> enemiesNearby = _entityDetector.DetectActors(ActorData.LogicalPosition, 3) .Where(e => ActorData.Team != e.Team) .Where(e => Vector2IntUtilities.IsOneTwoOrThreeSteps(e.LogicalPosition, ActorData.LogicalPosition)); // this code orientates the actor to face the closest danger, even if it means stepping backwards List <Vector2Int> directionsToOneStepEnemiesNearby = enemiesNearby.Select(e => e.LogicalPosition - ActorData.LogicalPosition) .Where(direction => Vector2IntUtilities.IsOneStep(direction)) .ToList(); List <Vector2Int> directionsToAllEnemiesNearby = enemiesNearby.Select(e => e.LogicalPosition - ActorData.LogicalPosition).ToList(); List <Vector2Int> directionsToRelevantEnemiesNearby = directionsToOneStepEnemiesNearby.Any() ? directionsToOneStepEnemiesNearby : directionsToAllEnemiesNearby; bool thereAreSomeEnemiesOnOneSide = directionsToRelevantEnemiesNearby.Any() && (directionsToRelevantEnemiesNearby.All(direction => direction.x < 0) || directionsToRelevantEnemiesNearby.All(direction => direction.x > 0)); if (thereAreSomeEnemiesOnOneSide) { _actorAligner.AlignActorToDirection(ActorData.Entity, directionsToRelevantEnemiesNearby.First().x); } else { _actorAligner.AlignActorToDirection(ActorData.Entity, ActorData.LogicalPosition.x - PreviousPosition.x); } if (entity.IsVisible) { entityAnimator.MoveTo(PreviousPosition, ActorData.LogicalPosition); } else { Vector3 animationTargetPosition = _gridInfoProvider.GetCellCenterWorld(ActorData.LogicalPosition); // The next line makes this class kind of untestable, because ActorData.Entity is a MonoBehaviour. I believe it must be so, // so that we can see and assign the reference to it in the inspector window. If this happens more often in other effects, // we could maybe extract some kind of proxy class to keep the Entity, so that we can test with fake proxy. entity.Position = animationTargetPosition; } if (!ActorData.ControlledByPlayer) { return; } ItemData itemOnTheGround = _entityDetector.DetectItems(ActorData.LogicalPosition).FirstOrDefault(); if (itemOnTheGround != null) { _uiConfig.TooltipPresenter.Present(itemOnTheGround.ItemDefinition, false); } }
private IGameAction ResolveActionForAggresion(ActorData actorData) { if (_rng.Check(0.04f)) { if (_gameContext.PlayerActor.ActorData.Health <= 0) { if (_rng.Check(0.07f)) { string text = _rng.Choice(new[] { "Ha, ha!", "I got him!", "I know my strength!", "Got what he deserved!", "Guess what we'll cook for dinner..." }); _textEffectPresenter.ShowTextEffect(actorData.LogicalPosition, text); } } else if (actorData.ActorType == ActorType.Dog && actorData.Team != Team.Beasts) { string text = _rng.Choice(new[] { "Woof", "Wrrrr!" }); _textEffectPresenter.ShowTextEffect(actorData.LogicalPosition, text); } else if (actorData.ActorType == ActorType.LastMonster) { var potential = new[] { "Whshsh!", "Rrrruv!" }.ToList(); if (!actorData.Entity.IsVisible) { potential.AddRange(new[] { "[THUD!]", "[THUD!]", "[THUD!]" }); } string text = _rng.Choice(potential); _textEffectPresenter.ShowTextEffect(actorData.LogicalPosition, text, text == "[THUD!]" ? Color.white : Color.magenta, true); } else if (actorData.ActorType == ActorType.Friend || actorData.ActorType == ActorType.Buddy) { string text = _rng.Choice(new[] { "Ma-uluh, ruv!", "Suku bgeve lir...", "Alir tak rettenekopast!" }); _textEffectPresenter.ShowTextEffect(actorData.LogicalPosition, text, new Color(0.7f, 0.8f, 1f)); } else if (actorData.ActorType != ActorType.Basher && actorData.ActorType != ActorType.LastMonster) { string text = _rng.Choice(new[] { "Back to your ward!", "Squeak!", "You're mine!", "Comrades, help me!", "Aah!" }); _textEffectPresenter.ShowTextEffect(actorData.LogicalPosition, text); } } List <ActorData> enemiesClose = _entityDetector.DetectActors(actorData.LogicalPosition, actorData.VisionRayLength) .Where(a => a.Team != actorData.Team && a.Entity.IsVisible) .ToList(); enemiesClose.Sort((first, second) => Vector2IntUtilities.WalkDistance(first.LogicalPosition, actorData.LogicalPosition) .CompareTo(Vector2IntUtilities.WalkDistance(second.LogicalPosition, actorData.LogicalPosition)) ); ActorData closestEnemy = enemiesClose.FirstOrDefault(); if (closestEnemy != null) { Vector2Int toEnemy = closestEnemy.LogicalPosition - actorData.LogicalPosition; // mam nadzieje, ze zadziala if (Vector2IntUtilities.WalkDistance(closestEnemy.LogicalPosition, actorData.LogicalPosition) == 2) { // move towards player if possible and desired bool possible = false; Vector2Int?legalMove = null; Vector2Int directionToEnemy = Vector2IntUtilities.Normalized(toEnemy); IEnumerable <Vector2Int> candidateMovesToEnemy = Vector2IntUtilities.GetCone(directionToEnemy) .Select(coneVector => coneVector - directionToEnemy) .Where(fixedConeVector => fixedConeVector != actorData.LogicalPosition); IList <Vector2Int> candidateMovesShuffled = _rng.Shuffle(candidateMovesToEnemy); foreach (var cand in candidateMovesShuffled) { if (!_entityDetector.DetectActors(actorData.LogicalPosition + cand).Any() && _gridInfoProvider.IsWalkable(actorData.LogicalPosition + cand)) { legalMove = cand; break; } } if (legalMove.HasValue) { int closeCombatAdvantage = actorData.WeaponWeld.WeaponDefinition.CloseCombatModifier - closestEnemy.WeaponWeld.WeaponDefinition.CloseCombatModifier; if (closeCombatAdvantage < 0) { closeCombatAdvantage = 0; } float chanceToMove = .1f + 0.2f * closeCombatAdvantage; if (_rng.Check(chanceToMove)) { return(_actionFactory.CreateMoveAction(actorData, legalMove.Value)); } } } if (Vector2IntUtilities.IsOneStep(toEnemy) || (actorData.WeaponWeld.WeaponDefinition.AllowsFarCombat && Vector2IntUtilities.IsOneOrTwoSteps(toEnemy) && _clearWayBetweenTwoPointsDetector.ClearWayExists(actorData.LogicalPosition, closestEnemy.LogicalPosition))) { IGameAction actionToPerform; bool pushingIsPossible = actorData.AiTraits.Contains(AiTrait.Pusher) && Vector2IntUtilities.IsOneStep(toEnemy) && _gridInfoProvider.IsWalkable(closestEnemy.LogicalPosition + toEnemy); bool pushingIsDesired = false; if (pushingIsPossible) { float pushingChanceScore = 0.08f; if (actorData.WeaponWeld.WeaponDefinition.CloseCombatModifier < closestEnemy.WeaponWeld.WeaponDefinition.CloseCombatModifier) { pushingChanceScore += .25f; } if (!_gridInfoProvider.IsWalkable(closestEnemy.LogicalPosition + toEnemy + toEnemy)) { pushingChanceScore += .2f; } if (_rng.Check(pushingChanceScore)) { pushingIsDesired = true; } } if (pushingIsPossible && pushingIsDesired) { actionToPerform = _actionFactory.CreatePushAction(actorData, closestEnemy); } else { bool isInGoodPosition = Vector2IntUtilities.IsOneStep(toEnemy) && actorData.WeaponWeld.WeaponDefinition.CloseCombatModifier > closestEnemy.WeaponWeld.WeaponDefinition.CloseCombatModifier; if (Vector2IntUtilities.IsOneOrTwoSteps(toEnemy) && !isInGoodPosition) // && actorData.AiTraits.Contains(AiTrait.Careful))) { float chanceToStepBack = 0f; float healthFactor = (1 - actorData.HealthProgress) * .15f; float swordsFactor = (closestEnemy.Swords - actorData.Swords) * .15f; chanceToStepBack = healthFactor + swordsFactor; if (_rng.Check(chanceToStepBack)) { Vector2Int directionFromEnemy = Vector2IntUtilities.Normalized(toEnemy) * -1; IEnumerable <Vector2Int> positionsToStepBack = Vector2IntUtilities.GetCone(directionFromEnemy) .Select(coneVector => actorData.LogicalPosition + coneVector - directionFromEnemy) .Where(position => position != actorData.LogicalPosition); foreach (var conePosition in positionsToStepBack) { if (!_gridInfoProvider.IsWalkable(conePosition) || _entityDetector.DetectEntities(conePosition).Any()) { continue; } Vector2Int stepBackMoveVector = conePosition - actorData.LogicalPosition; return(_actionFactory.CreateMoveAction(actorData, stepBackMoveVector)); } } } bool isDaringBlow = false; if (actorData.Traits.Contains(Trait.DaringBlow) && actorData.Swords >= 2) { float daringBlowChance = actorData.AiTraits.Contains(AiTrait.Aggressive) ? .5f : .2f; if (actorData.ActorType == ActorType.Basher) { daringBlowChance += .2f; } if (_rng.Check(daringBlowChance)) { isDaringBlow = true; } } actionToPerform = _actionFactory.CreateAttackAction(actorData, closestEnemy, isDaringBlow); } if (DateTime.UtcNow < closestEnemy.BlockedUntil) { actorData.StoredAction = actionToPerform; actorData.BlockedUntil = closestEnemy.BlockedUntil; return(null); } return(actionToPerform); } int moveX = toEnemy.x.CompareTo(0); int moveY = toEnemy.y.CompareTo(0); Vector2Int moveVector = new Vector2Int(moveX, moveY); Func <Vector2Int, bool> isWalkableAndFree = position => _gridInfoProvider.IsWalkable(position) && !_entityDetector.DetectActors(position).Any(); if (!isWalkableAndFree(actorData.LogicalPosition + moveVector)) { Vector2Int?finalMoveVector = null; Vector2Int alternativeMoveVector1; Vector2Int alternativeMoveVector2; // trying to find best alternative vectors to move if (moveVector.x == 0) { alternativeMoveVector1 = new Vector2Int(+1, moveVector.y); alternativeMoveVector2 = new Vector2Int(-1, moveVector.y); } else if (moveVector.y == 0) { alternativeMoveVector1 = new Vector2Int(moveVector.x, -1); alternativeMoveVector2 = new Vector2Int(moveVector.x, +1); } else { alternativeMoveVector1 = new Vector2Int(moveVector.x, 0); alternativeMoveVector2 = new Vector2Int(0, moveVector.y); } if (isWalkableAndFree(actorData.LogicalPosition + alternativeMoveVector1)) { finalMoveVector = alternativeMoveVector1; } else if (isWalkableAndFree(actorData.LogicalPosition + alternativeMoveVector2)) { finalMoveVector = alternativeMoveVector2; } if (finalMoveVector.HasValue) { return(_actionFactory.CreateMoveAction(actorData, finalMoveVector.Value)); } return(_actionFactory.CreatePassAction(actorData)); } return(_actionFactory.CreateMoveAction(actorData, moveVector)); } else if (actorData.Team == Team.Beasts) { ActorData playerClose = _entityDetector.DetectActors(actorData.LogicalPosition, actorData.VisionRayLength).FirstOrDefault( f => f != actorData && f.ActorType == ActorType.Player); if (playerClose != null) { Vector2Int toFriend = playerClose.LogicalPosition - actorData.LogicalPosition; Vector2Int directionToFriend = Vector2IntUtilities.Normalized(toFriend); Vector2Int legalMove = new Vector2Int(); IEnumerable <Vector2Int> candidateMovesToFriend = Vector2IntUtilities.GetCone(directionToFriend) .Select(coneVector => coneVector - directionToFriend) .Where(fixedConeVector => fixedConeVector != actorData.LogicalPosition); IList <Vector2Int> candidateMovesShuffled = _rng.Shuffle(candidateMovesToFriend); foreach (var cand in candidateMovesShuffled) { if (!_entityDetector.DetectActors(actorData.LogicalPosition + cand).Any() && _gridInfoProvider.IsWalkable(actorData.LogicalPosition + cand)) { legalMove = cand; break; } } Vector2Int moveVector = legalMove; if (!_entityDetector.DetectActors(actorData.LogicalPosition + moveVector).Any()) { return(_actionFactory.CreateMoveAction(actorData, moveVector)); } } return(_actionFactory.CreatePassAction(actorData)); } if (Vector2IntUtilities.WalkDistance(actorData.LogicalPosition, _gameContext.PlayerActor.ActorData.LogicalPosition) < 15 && _gameContext.PlayerActor.ActorData.Health > 0 && actorData.ActorType != ActorType.Basher) { Vector2Int?farReachablePoint = GetFarReachablePoint(actorData); if (farReachablePoint.HasValue) { Vector2Int moveVector = Vector2IntUtilities.Normalized(farReachablePoint.Value - actorData.LogicalPosition); return(_actionFactory.CreateMoveAction(actorData, moveVector)); } } return(_actionFactory.CreatePassAction(actorData)); }
private void PlaceTilesBasingOnDungeon(BoundsInt gridBounds, Dungeon generator) { bool stairsGenerated = false; foreach (Vector3Int position in gridBounds.allPositionsWithin) { Vector2Int position2D = position.ToVector2Int(); GenTile genTile = generator.GetCellType(position2D.x, position2D.y); switch (genTile) { case GenTile.DirtFloor: { _gameContext.DirtTilemap.SetTile(position, Dirt); if (_rng.Check(0.03f)) { _gameContext.EnvironmentTilemap.SetTile(position, _rng.Choice(FloorEnvironmetals)); } if (_rng.Check(0.06f)) { if (Vector2IntUtilities.Neighbours8(position2D).All(n => generator.GetCellType(n.x, n.y) == GenTile.DirtFloor)) { _gameContext.ObjectsTilemap.SetTile(position, _rng.Choice(WallEnvironmetals)); } } break; } case GenTile.Corridor: { _gameContext.DirtTilemap.SetTile(position, Dirt); break; } case GenTile.StoneWall: case GenTile.DirtWall: { _gameContext.WallsTilemap.SetTile(position, Wall); if (_rng.Check(0.04f)) { _gameContext.EnvironmentTilemap.SetTile(position, _rng.Choice(WallAttachmentEnvironmetals)); } break; } case GenTile.Upstairs: { _gameContext.DirtTilemap.SetTile(position, Dirt); _gameContext.EnvironmentTilemap.SetTile(position, StairsUp); _gameContext.WallsTilemap.SetTile(position, null); stairsGenerated = true; break; } case GenTile.Downstairs: { _gameContext.DirtTilemap.SetTile(position, Dirt); break; } case GenTile.Door: { _gameContext.DirtTilemap.SetTile(position, Dirt); GenTile tileToRight = generator.GetCellType(position.x + 1, position.y); bool isHorizontalDoor = tileToRight == GenTile.Corridor || tileToRight == GenTile.DirtFloor; bool doorsAreOpen = _rng.Check(0.3f); if (doorsAreOpen) { _gameContext.EnvironmentTilemap.SetTile(position, isHorizontalDoor ? DoorsHorizontalOpen : DoorsVerticalOpen); } else { _gameContext.WallsTilemap.SetTile(position, isHorizontalDoor ? DoorsHorizontalClosed : DoorsVerticalClosed); } break; } default: { break; } } } if (!stairsGenerated) { BoundsInt randomRoom = _rng.Choice(generator.Rooms); Vector3Int center = BoundsIntUtilities.Center(randomRoom).ToVector3Int(); _gameContext.DirtTilemap.SetTile(center, Dirt); _gameContext.EnvironmentTilemap.SetTile(center, StairsUp); _gameContext.WallsTilemap.SetTile(center, null); Debug.Log("Missing stairs in dungeon! Generating in random room on position: " + center); } }
private void GenerateActorsInDungeon(Dungeon currentDungeon, DungeonConfig dungeonConfig, bool isFirstDungeon) { BoundsInt playerRoom = new BoundsInt(); if (isFirstDungeon) { BoundsInt furthestRoomToStairs = FurthestRoomToStairsResolver.GetFurthestRoomToStairs(currentDungeon); playerRoom = furthestRoomToStairs; BoundsInt roomToSpawnPlayerIn = playerRoom; Vector2Int playerPosition = BoundsIntUtilities.Center(roomToSpawnPlayerIn); Vector2Int breadPosition = Vector2Int.zero; var neighboursRebourse = Vector2IntUtilities.Neighbours8(playerPosition).ToList(); neighboursRebourse.Reverse(); foreach (var neighbour in neighboursRebourse) { if (_gridInfoProvider.IsWalkable(neighbour) && neighbour != playerPosition) { _entitySpawner.SpawnItem(BreadItem, neighbour); breadPosition = neighbour; break; } } foreach (var neighbour in neighboursRebourse) { if (neighbour != breadPosition && _gridInfoProvider.IsWalkable(neighbour)) { _entitySpawner.SpawnItem(KeyItem, neighbour); break; } } BoundsInt aroundPlayerRoom = new BoundsInt(playerRoom.position - new Vector3Int(1, 1, 0), playerRoom.size + new Vector3Int(2, 2, 0)); foreach (Vector3Int positionInPlayerRoom in aroundPlayerRoom.allPositionsWithin) { if (_gameContext.WallsTilemap.GetTile(positionInPlayerRoom) == DoorsVerticalClosed || _gameContext.EnvironmentTilemap.GetTile(positionInPlayerRoom) == DoorsVerticalOpen) { _gameContext.WallsTilemap.SetTile(positionInPlayerRoom, HeavyDoorsVerticalClosed); _gameContext.EnvironmentTilemap.SetTile(positionInPlayerRoom, null); } if (_gameContext.WallsTilemap.GetTile(positionInPlayerRoom) == DoorsHorizontalClosed || _gameContext.EnvironmentTilemap.GetTile(positionInPlayerRoom) == DoorsHorizontalOpen) { _gameContext.WallsTilemap.SetTile(positionInPlayerRoom, HeavyDoorsHorizontalClosed); _gameContext.EnvironmentTilemap.SetTile(positionInPlayerRoom, null); } } var playerActorBehaviour = _entitySpawner.SpawnActor(ActorType.Player, playerPosition); playerActorBehaviour.ActorData.ControlledByPlayer = true; _gameContext.PlayerActor = playerActorBehaviour; _gameConfig.FollowPlayerCamera.Follow = playerActorBehaviour.transform; _uiConfig.Arrows.transform.parent = playerActorBehaviour.transform; _uiConfig.Arrows.transform.localPosition = new Vector3(0, -0.1f, 0); } foreach (BoundsInt room in currentDungeon.Rooms.Skip(isFirstDungeon ? 1 :0)) { if (room == playerRoom) { continue; } float populationValue = _rng.NextFloat(); int populationInRoom = Mathf.RoundToInt(dungeonConfig.ChanceToRoomPopulation.Evaluate(populationValue)); for (int i = 0; i < populationInRoom; i++) { ActorDefinition[] actorTypesAvailable = dungeonConfig.EnemiesToSpawn; ActorType actorTypeChosen = _rng.Choice(actorTypesAvailable).ActorType; Vector2Int centralPosition = BoundsIntUtilities.Center(room); _entitySpawner.SpawnActor(actorTypeChosen, centralPosition); } } _entitySpawner.SpawnActor(dungeonConfig.BossToSpawn.ActorType, currentDungeon.StairsLocation, true); }
public IGameAction GetAction(ActorData actorData) { if (_inputHolder.PlayerInput == PlayerInput.None) { return(null); } if (_inputHolder.PlayerInput != PlayerInput.UseCurrentItem && _inputHolder.PlayerInput != PlayerInput.DropCurrentItem) { _uiConfig.ItemHolder.DeselectItem(); _uiConfig.TooltipPresenter.Panel.gameObject.SetActive(false); _uiConfig.TooltipCurrentWeaponPresenter.gameObject.SetActive(false); _uiConfig.TooltipCurrentWeaponPresenter.GetComponent <CurrentWeaponTooltip>().LabelWearingUpper.gameObject.SetActive(false); var quitButton = GameObject.FindGameObjectWithTag("button_quit"); if (quitButton != null) { quitButton.SetActive(false); } } if (_uiConfig.WalkAbilityButton.GetComponentInChildren <Text>() != null) { _uiConfig.WalkAbilityButton.GetComponentInChildren <Text>().gameObject.SetActive(false); } if (_uiConfig.DaringBlowAbilityButton.GetComponentInChildren <Text>() != null) { _uiConfig.DaringBlowAbilityButton.GetComponentInChildren <Text>().gameObject.SetActive(false); } if (_uiConfig.PushAbilityButton.GetComponentInChildren <Text>() != null) { _uiConfig.PushAbilityButton.GetComponentInChildren <Text>().gameObject.SetActive(false); } IGameAction gameActionToReturn; if (_inputHolder.PlayerInput == PlayerInput.PickUp) { IList <ItemData> items = _entityDetector.DetectItems(actorData.LogicalPosition).ToList(); bool allSlotsOccupied = _uiConfig.ItemHolder.Items.All(i => i != null); if (!items.Any() || allSlotsOccupied) { return(null); } ItemData itemToPickUp = items.First(); _inputHolder.PlayerInput = PlayerInput.None; return(_actionFactory.CreatePickUpAction(actorData, itemToPickUp)); } if (_inputHolder.PlayerInput == PlayerInput.Drop) { ItemData firstItem = actorData.Items.FirstOrDefault(); if (firstItem == null) { return(null); } _inputHolder.PlayerInput = PlayerInput.None; return(_actionFactory.CreateDropAction(actorData, firstItem)); } if (_inputHolder.PlayerInput == PlayerInput.Catch) { ActorData caughtActor = _entityDetector.DetectActors(actorData.LogicalPosition, 1).FirstOrDefault(); if (caughtActor == null) { return(null); } _inputHolder.PlayerInput = PlayerInput.None; return(_actionFactory.CreateCatchAction(actorData, caughtActor)); } if (_inputHolder.PlayerInput == PlayerInput.Release) { if (actorData.CaughtActor == null) { return(null); } _inputHolder.PlayerInput = PlayerInput.None; return(_actionFactory.CreateReleaseAction(actorData)); } if (_inputHolder.PlayerInput == PlayerInput.Pass) { _inputHolder.PlayerInput = PlayerInput.None; return(_actionFactory.CreatePassAction(actorData)); } if (_inputHolder.PlayerInput == PlayerInput.Eat) { _inputHolder.PlayerInput = PlayerInput.None; ItemData foodAtFeet = _entityDetector.DetectItems(actorData.LogicalPosition).FirstOrDefault(i => i.ItemType == ItemType.DeadBody); if (foodAtFeet == null) { return(null); } return(_actionFactory.CreateEatAction(actorData, foodAtFeet)); } if (_inputHolder.PlayerInput == PlayerInput.UseCurrentItem) { _inputHolder.PlayerInput = PlayerInput.None; ItemDefinition item; item = _uiConfig.ItemHolder.CurrentItem(); if (item == null) { ItemData itemAtFeet = _entityDetector.DetectItems(actorData.LogicalPosition).FirstOrDefault(); if (itemAtFeet != null) { item = itemAtFeet.ItemDefinition; return(_actionFactory.CreateUseItemAction(actorData, item, false)); } return(null); } return(_actionFactory.CreateUseItemAction(actorData, item, true)); } if (_inputHolder.PlayerInput == PlayerInput.DropCurrentItem) { _inputHolder.PlayerInput = PlayerInput.None; ItemDefinition item = _uiConfig.ItemHolder.CurrentItem(); if (item == null) { return(null); } return(_actionFactory.CreateDropItemAction(actorData, item)); } if (_inputHolder.PlayerInput == PlayerInput.Ascend) { TileBase stairsDown = Resources.Load <TileBase>("Tiles/Environment/Stairs_down"); _inputHolder.PlayerInput = PlayerInput.None; Vector2Int playerPosition = _gameContext.PlayerActor.ActorData.LogicalPosition; TileBase envTileBelowPlayer = _gameContext.EnvironmentTilemap.GetTile(playerPosition.ToVector3Int()); if (envTileBelowPlayer != null && envTileBelowPlayer != stairsDown) { return(_actionFactory.CreateAscendAction(actorData)); } return(null); } Vector2Int actionVector = GetActionVector(_inputHolder.PlayerInput); Vector2Int targetPosition = actionVector + actorData.LogicalPosition; if (_inputHolder.PlayerInputModifier == PlayerInputModifier.Move) { _inputHolder.PlayerInputModifier = PlayerInputModifier.None; _inputHolder.PlayerInput = PlayerInput.None; _arrowsVisibilityManager.Hide(); IEnumerable <ActorData> actorsAtTarget = _entityDetector.DetectActors(targetPosition); if (actorsAtTarget.Any()) { return(null); } gameActionToReturn = _actionFactory.CreateMoveAction(actorData, actionVector); return(gameActionToReturn); } bool isAggressiveAttack = false; if (_inputHolder.PlayerInputModifier == PlayerInputModifier.DaringBlow) { isAggressiveAttack = true; _inputHolder.PlayerInputModifier = PlayerInputModifier.None; _inputHolder.PlayerInput = PlayerInput.None; _weaponColorizer.Decolorize((actorData.Entity as ActorBehaviour).WeaponAnimator); } IList <Vector2Int> targetPositionsCone = Vector2IntUtilities.GetCone(actionVector) .Select(zeroBasedPosition => actorData.LogicalPosition + zeroBasedPosition) .ToList(); IList <ActorData> actorsCloseToCone = _entityDetector.DetectActors(targetPosition, 2).ToList(); ActorData targetActor; ActorData actorAtTargetPosition = actorsCloseToCone.FirstOrDefault(a => a.LogicalPosition == targetPosition); if (actorAtTargetPosition != null && actorAtTargetPosition.Team == actorData.Team) { _inputHolder.PlayerInput = PlayerInput.None; gameActionToReturn = _actionFactory.CreateDisplaceAction(actorData, actorAtTargetPosition); return(gameActionToReturn); } bool isPushing = _inputHolder.PlayerInputModifier == PlayerInputModifier.Push; _arrowsVisibilityManager.Hide(); _inputHolder.PlayerInputModifier = PlayerInputModifier.None; if ((actorAtTargetPosition != null || isPushing) || actorData.WeaponWeld.WeaponDefinition.AllowsFarCombat == false) { targetActor = actorAtTargetPosition; } else { targetActor = actorsCloseToCone .FirstOrDefault(potentialTarget => potentialTarget.Team != actorData.Team && targetPositionsCone.Contains(potentialTarget.LogicalPosition) && _clearWayBetweenTwoPointsDetector.ClearWayExists(actorData.LogicalPosition, potentialTarget.LogicalPosition)); } if (targetActor != null) // hit! { gameActionToReturn = isPushing ? _actionFactory.CreatePushAction(actorData, targetActor) : _actionFactory.CreateAttackAction(actorData, targetActor, isAggressiveAttack); } else { TileBase wallTileAtTarget = _gameContext.WallsTilemap.GetTile(targetPosition.ToVector3Int()); if (wallTileAtTarget != null) { _heavyDoorsHClosedTile = Resources.Load <Tile>("Tiles/Environment/doors_HEAVY_0"); _heavyDoorsVClosedTile = Resources.Load <Tile>("Tiles/Environment/doors_HEAVY_2"); if ((wallTileAtTarget == _heavyDoorsHClosedTile || wallTileAtTarget == _heavyDoorsVClosedTile) && _uiConfig.ItemHolder.Items.Where(i => i != null).All(i => i.Name != "Key") && _gameContext.PlayerActor.ActorData.WeaponWeld.Name != "Key") { // bump gameActionToReturn = _actionFactory.CreateMoveAction(actorData, actionVector); _textEffectPresenter.ShowTextEffect(actorData.LogicalPosition, "Umph! Locked!", Color.yellow); } else { var doorsHClosedTile = Resources.Load <Tile>("Tiles/Environment/doors_H_closed"); var doorsVClosedTile = Resources.Load <Tile>("Tiles/Environment/doors_V_closed"); if (wallTileAtTarget == doorsHClosedTile || wallTileAtTarget == doorsVClosedTile) { bool isHorizontal = wallTileAtTarget == doorsHClosedTile; gameActionToReturn = _actionFactory.CreateOpenDoorAction(actorData, targetPosition, isHorizontal); } else if (wallTileAtTarget == _heavyDoorsHClosedTile || wallTileAtTarget == _heavyDoorsVClosedTile) { bool isHorizontal = wallTileAtTarget == _heavyDoorsHClosedTile; gameActionToReturn = _actionFactory.CreateOpenDoorAction(actorData, targetPosition, isHorizontal, true); } else { gameActionToReturn = _actionFactory.CreateMoveAction(actorData, actionVector); } } } else { gameActionToReturn = _actionFactory.CreateMoveAction(actorData, actionVector); } } _inputHolder.PlayerInput = PlayerInput.None; return(gameActionToReturn); }
//and here's the one generating the whole map public bool CreateDungeon(Vector3Int gridBoundsMin, int inx, int iny, int inobj) { _offset = gridBoundsMin; this._objects = inobj < 1 ? 10 : inobj; // adjust the size of the map, if it's smaller or bigger than the limits if (inx < 3) { this._xsize = 3; } else if (inx > xmax) { this._xsize = xmax; } else { this._xsize = inx; } if (iny < 3) { this._ysize = 3; } else if (iny > ymax) { this._ysize = ymax; } else { this._ysize = iny; } Console.WriteLine(MsgXSize + this._xsize); Console.WriteLine(MsgYSize + this._ysize); Console.WriteLine(MsgMaxObjects + this._objects); // redefine the map var, so it's adjusted to our new map size this._dungeonMap = new GenTile[this._xsize * this._ysize]; // start with making the "standard stuff" on the map this.Initialize(); /******************************************************************************* * And now the code of the random-map-generation-algorithm begins! *******************************************************************************/ // start with making a room in the middle, which we can start building upon this.MakeRoom(this._xsize / 2, this._ysize / 2, _roomSizeMaxX, _roomSizeMaxY, RandomDirection()); // getrand saken f????r att slumpa fram riktning p?? rummet // keep count of the number of "objects" we've made int currentFeatures = 1; // +1 for the first room we just made // then we sart the main loop for (int countingTries = 0; countingTries < 1000; countingTries++) { // check if we've reached our quota if (currentFeatures == this._objects) { break; } // start with a random wall int newx = 0; int xmod = 0; int newy = 0; int ymod = 0; Direction?validTile = null; // 1000 chances to find a suitable object (room or corridor).. for (int testing = 0; testing < 1000; testing++) { newx = this.GetRand(1, this._xsize - 1); newy = this.GetRand(1, this._ysize - 1); if (GetCellTypeNoOffset(newx, newy) == GenTile.DirtWall || GetCellTypeNoOffset(newx, newy) == GenTile.Corridor) { var surroundings = this.GetSurroundings(new Vector2Int(newx, newy)); // check if we can reach the place var canReach = surroundings.FirstOrDefault(s => s.Item2.Item2 == GenTile.Corridor || s.Item2.Item2 == GenTile.DirtFloor); if (canReach == null) { continue; } validTile = canReach.Item2.Item1; switch (canReach.Item2.Item1) { case Direction.North: xmod = 0; ymod = -1; break; case Direction.East: xmod = 1; ymod = 0; break; case Direction.South: xmod = 0; ymod = 1; break; case Direction.West: xmod = -1; ymod = 0; break; default: throw new InvalidOperationException(); } // check that we haven't got another door nearby, so we won't get alot of openings besides // each other if (GetCellTypeNoOffset(newx, newy + 1) == GenTile.Door) // north { validTile = null; } else if (GetCellTypeNoOffset(newx - 1, newy) == GenTile.Door) // east { validTile = null; } else if (GetCellTypeNoOffset(newx, newy - 1) == GenTile.Door) // south { validTile = null; } else if (GetCellTypeNoOffset(newx + 1, newy) == GenTile.Door) // west { validTile = null; } // if we can, jump out of the loop and continue with the rest if (validTile.HasValue) { break; } } } if (validTile.HasValue) { // choose what to build now at our newly found place, and at what direction int feature = this.GetRand(0, 100); if (feature <= ChanceRoom) { // a new room if (this.MakeRoom(newx + xmod, newy + ymod, 8, 6, validTile.Value)) { currentFeatures++; // add to our quota // then we mark the wall opening with a door this.SetCell(newx, newy, GenTile.Door); // clean up infront of the door so we can reach it this.SetCell(newx + xmod, newy + ymod, GenTile.DirtFloor); } } else if (feature >= ChanceRoom) { // new corridor if (this.MakeCorridor(newx + xmod, newy + ymod, 6, validTile.Value)) { // same thing here, add to the quota and a door currentFeatures++; this.SetCell(newx, newy, GenTile.Door); } } } } /******************************************************************************* * All done with the building, let's finish this one off *******************************************************************************/ AddSprinkles(); // all done with the map generation, tell the user about it and finish Console.WriteLine(MsgNumObjects + currentFeatures); for (int y = 0; y < this._ysize; y++) { for (int x = 0; x < this._xsize; x++) { if (GetCellTypeNoOffset(x, y) == GenTile.Corridor) { List <Vector2Int> neighbours = Vector2IntUtilities.Neighbours8(new Vector2Int(x, y)); foreach (Vector2Int neighbour in neighbours) { GenTile neighbourCell = GetCellTypeNoOffset(neighbour.x, neighbour.y); if (neighbourCell == GenTile.Unused) { SetCell(neighbour.x, neighbour.y, GenTile.StoneWall); } } } } } return(true); }
public void Heartbeat(ActorData actorData) { ++actorData.RoundsCount; BoundsInt lastLevelBounds = new BoundsInt(-18, -103, 0, 49, 72, 1); BoundsInt almostLastLevelBounds = new BoundsInt(-16, -101, 0, 45, 68, 1); if (actorData.ActorType == ActorType.Player && _gameContext.CurrentDungeonIndex >= _gameContext.Dungeons.Count && !almostLastLevelBounds.Contains(actorData.LogicalPosition.ToVector3Int())) { _textEffectPresenter.ShowTextEffect(actorData.LogicalPosition, "Almost free!", Color.yellow); } if (actorData.ActorType == ActorType.Player && _gameContext.CurrentDungeonIndex >= _gameContext.Dungeons.Count && !lastLevelBounds.Contains(actorData.LogicalPosition.ToVector3Int())) { var finisher = _uiConfig.GameFinisher; finisher.gameObject.SetActive(true); finisher.Initialize(actorData); } //if (actorData.Health < actorData.MaxHealth) // ++actorData.Health; IEnumerable <ActorData> enemiesNearby = _entityDetector.DetectActors(actorData.LogicalPosition, 2) .Where(a => a.Team != actorData.Team); if (enemiesNearby.Any(a => Vector2IntUtilities.IsOneStep(a.LogicalPosition, actorData.LogicalPosition))) { actorData.IsInCloseCombat = true; } else { actorData.IsInCloseCombat = false; } actorData.HasLittleSpace = _playerSpaceResolver.ResolveIfPlayerHasLittleSpace(actorData); int maxSwords = _maxSwordCalculator.Calculate(actorData); actorData.MaxSwords = maxSwords; if (actorData.Swords > maxSwords) { actorData.Swords = maxSwords; } if (actorData.Swords < maxSwords) { if (actorData.WeaponWeld.WeaponDefinition.RecoveryTime == RecoveryTime.ThreePerSeven) { int roundNumber = actorData.RoundsCount % 21; if (new[] { 0, 3, 5, 8, 10, 13, 15, 18, 20 }.Contains(roundNumber)) { ++actorData.Swords; } } else if (actorData.WeaponWeld.WeaponDefinition.RecoveryTime == RecoveryTime.OnePerTwo && actorData.RoundsCount % 2 == 0) { ++actorData.Swords; } else if (actorData.WeaponWeld.WeaponDefinition.RecoveryTime == RecoveryTime.ThreePerFive) { int roundNumber = actorData.RoundsCount % 15; if (new[] { 0, 2, 5, 7, 10, 12 }.Contains(roundNumber)) { ++actorData.Swords; } } } if (actorData.Entity.transform.GetComponentInChildren <SwordsIndicator>() == null /*inactive*/) { } else { actorData.Entity.transform.GetComponentInChildren <SwordsIndicator>().UpdateActiveSwords(actorData.Swords); // kind of ugly workaround, but seems to help } if (actorData.ControlledByPlayer) { if (actorData.Xp >= _gameConfig.XpForLevels[actorData.Level + 1]) { ++actorData.Level; _uiConfig.AdvanceManager.gameObject.SetActive(true); GameObject.Find("PlayerLevelIndicator").GetComponent <Text>().text = "Player level: " + actorData.Level; } } }