Пример #1
0
        /// <summary>
        /// Setup new game variables. This involves creating the player, and generating the game map.
        /// </summary>
        /// <param name="player">Player</param>
        /// <param name="gameMap">Game map</param>
        public static void SetupGameVariables(ref EntityID player, ref GameMap gameMap)
        {
            EntityStore.Clear();

            player = EntityFunctions.CreatePlayer(new Vector2i(-1, -1));

            gameMap = new GameMap(new Vector2i(C.MAP_WIDTH, C.MAP_HEIGHT));
            gameMap.MakeMap(C.MAX_ROOMS, C.ROOM_MIN_SIZE, C.ROOM_MAX_SIZE, C.MAP_WIDTH, C.MAP_HEIGHT, player);

            if (player.e.moveTrail != null)
            {
                player.e.moveTrail.Clear();
            }
        }
Пример #2
0
        /// <summary>
        /// Move towards target position, by one tile
        /// </summary>
        /// <param name="targetPos">Target position</param>
        public void MoveTowards(Vector2i targetPos)
        {
            var game = (RetroDungeoneerGame)RB.Game;

            var delta    = targetPos - pos;
            var distance = delta.Magnitude();

            // Normalize
            delta.x = Mathf.RoundToInt(delta.x / distance);
            delta.y = Mathf.RoundToInt(delta.y / distance);

            if (!(game.map.IsBlocked(pos + delta) || !EntityFunctions.GetBlockingEntityAtPos(pos + delta).isEmpty))
            {
                pos += delta;
            }
        }
Пример #3
0
        private void PlaceEntities(Rect2i room, int numOfItems, int numOfMonsters)
        {
            var mMonsterChances = EntityFunctions.GetMonsterChances(dungeonLevel);
            var mItemChances    = EntityFunctions.GetItemChances(dungeonLevel);

            // Place monsters
            var existingMonsterPositions = new List <Vector2i>();

            for (int i = 0; i < numOfMonsters; i++)
            {
                var randomPos = new Vector2i(
                    Random.Range(room.min.x + 1, room.max.x),
                    Random.Range(room.min.y + 1, room.max.y));

                if (!existingMonsterPositions.Contains(randomPos))
                {
                    var monsterType = (MonsterType)RandomUtils.RandomChoiceIndex(mMonsterChances);
                    var monster     = EntityFunctions.CreateMonster(monsterType, randomPos);

                    if (!monster.isEmpty)
                    {
                        existingMonsterPositions.Add(randomPos);
                    }
                }
            }

            // Place items
            var existingItemPositions = new List <Vector2i>();

            for (int i = 0; i < numOfItems; i++)
            {
                var randomPos = new Vector2i(
                    Random.Range(room.min.x + 1, room.max.x),
                    Random.Range(room.min.y + 1, room.max.y));

                if (!existingItemPositions.Contains(randomPos))
                {
                    var itemType = (ItemType)RandomUtils.RandomChoiceIndex(mItemChances);
                    var item     = EntityFunctions.CreateItem(itemType, randomPos);

                    if (!item.isEmpty)
                    {
                        existingItemPositions.Add(randomPos);
                    }
                }
            }
        }
        /// <summary>
        /// Initialize your game here.
        /// </summary>
        /// <returns>Return true if successful</returns>
        public bool Initialize()
        {
            assets.LoadAll();

            // You can load a spritesheet here
            RB.SpriteSheetSet(assets.spriteSheet);

            RB.EffectSet(RB.Effect.Scanlines, 0.5f);

            EntityFunctions.Initialize();
            S.InitializeAnims();

            SoundSerializer.Initialize();

            InitializeNewGame.InitializeConstants();

            RenderFunctions.Initialize();

            mSceneGame     = new SceneGame();
            mSceneMainMenu = new SceneMainMenu();
            mSceneMessage  = new SceneMessage();

            // Generate tile grid, this is a one time operation, we can keep reusing the grid
            var gridColor = Color.white;

            for (int x = 0; x < RB.MapSize.width; x++)
            {
                for (int y = 0; y < RB.MapSize.height; y++)
                {
                    RB.MapSpriteSet(C.LAYER_GRID, new Vector2i(x, y), S.GRID, gridColor);
                }
            }

            ChangeScene(SceneEnum.MAIN_MENU);

            RB.MapLayerSpriteSheetSet(C.LAYER_GRID, assets.spriteSheet);
            RB.MapLayerSpriteSheetSet(C.LAYER_TERRAIN, assets.spriteSheet);
            RB.MapLayerSpriteSheetSet(C.LAYER_VISIBILITY, assets.spriteSheet);

            // Collect any garbage created during initilization to avoid a performance hiccup later.
            System.GC.Collect();

            return(true);
        }
Пример #5
0
        private void HandleResult(ResultSet resultSet, Result result, out bool tookTurn)
        {
            tookTurn = false;
            var game = (RetroDungeoneerGame)RB.Game;

            switch (result.type)
            {
            case Result.Type.Move:
            {
                Vector2i delta = result.veci1;
                if ((delta.x != 0 || delta.y != 0) && !mGameMap.IsBlocked(mPlayer.e.pos + delta))
                {
                    var destPos      = mPlayer.e.pos + delta;
                    var targetEntity = EntityFunctions.GetBlockingEntityAtPos(destPos);

                    if (!targetEntity.isEmpty)
                    {
                        mPlayer.e.fighter.Attack(mResultSet, targetEntity);
                    }
                    else
                    {
                        var  entities   = EntityFunctions.GetEntitiesAtPos(mPlayer.e.pos);
                        bool stuckInWeb = false;
                        for (int i = 0; i < entities.Count; i++)
                        {
                            if (entities[i].e.groundTrigger != null && entities[i].e.groundTrigger.type == GroundTrigger.GroundTriggerType.Web)
                            {
                                stuckInWeb = true;
                                break;
                            }
                        }

                        // Attempt to free from web
                        if (stuckInWeb)
                        {
                            if (Random.Range(0, 6) == 0)
                            {
                                stuckInWeb = false;
                                resultSet.AddMessage(C.FSTR.Set("You manage to free yourself from the web."));
                            }
                        }

                        if (!stuckInWeb)
                        {
                            mPlayer.e.Move(delta);
                            mFOVRecompute = true;

                            RB.SoundPlay(game.assets.soundFootStep, 0.66f, RandomUtils.RandomPitch(0.1f));

                            var entitesAtDest = EntityFunctions.GetEntitiesAtPos(mPlayer.e.pos);
                            for (int i = 0; i < entitesAtDest.Count; i++)
                            {
                                var trigger = entitesAtDest[i].e.groundTrigger;
                                if (trigger != null)
                                {
                                    trigger.Trigger(resultSet);
                                }
                            }
                        }
                        else
                        {
                            resultSet.AddMessage(C.FSTR.Set("You fail to free yourself from the web, keep trying."));
                            RB.SoundPlay(game.assets.soundWeb, 0.5f, RandomUtils.RandomPitch(0.1f));
                        }
                    }

                    mFloodRecompute = true;

                    tookTurn = true;
                }
                else if (delta.x == 0 && delta.y == 0)
                {
                    // Do nothing, wait
                    tookTurn = true;
                }
            }

            break;

            case Result.Type.Exit:
                if (mGameState == GameState.SHOW_INVENTORY ||
                    mGameState == GameState.DROP_INVENTORY ||
                    mGameState == GameState.SHOW_HELP ||
                    mGameState == GameState.CHARACTER_SCREEN)
                {
                    RB.SoundPlay(game.assets.soundMenuClose, 1, RandomUtils.RandomPitch(0.1f));
                    ChangeState(mPreviousGameState);
                }
                else if (mGameState == GameState.TARGETING)
                {
                    resultSet.AddTargetingCancelled();
                }
                else
                {
                    // Exit back to main menu
                    game.ChangeScene(SceneEnum.MAIN_MENU);
                }

                break;

            case Result.Type.Message:
                mConsole.Log(result.str1);
                break;

            case Result.Type.Dead:
                if (result.entity1 == mPlayer)
                {
                    DeathFunctions.KillPlayer(mResultSet, result.entity1);
                    ChangeState(GameState.PLAYER_DEAD);
                }
                else
                {
                    DeathFunctions.KillMonster(mResultSet, result.entity1);
                }

                break;

            case Result.Type.Pickup:
            {
                var receiver = result.entity1;
                if (receiver.e.inventory == null)
                {
                    break;
                }

                var entityList = EntityFunctions.GetEntitiesAtPos(receiver.e.pos);
                if (entityList != null)
                {
                    for (int j = 0; j < entityList.Count; j++)
                    {
                        var e = entityList[j].e;

                        if (e.item != null)
                        {
                            receiver.e.inventory.AddItem(resultSet, e.id);
                        }
                    }
                }
            }

            break;

            case Result.Type.ItemAdded:
                result.entity1.e.renderOrder = RenderFunctions.RenderOrder.HIDDEN;
                result.entity1.e.pos         = new Vector2i(-1, -1);

                RB.SoundPlay(game.assets.soundInventory, 1, RandomUtils.RandomPitch(0.1f));

                break;

            case Result.Type.ShowInventory:
                if (mGameState != GameState.SHOW_INVENTORY)
                {
                    ChangeState(GameState.SHOW_INVENTORY);
                }
                else
                {
                    ChangeState(mPreviousGameState);
                }

                break;

            case Result.Type.InventoryIndex:
            {
                var entity = result.entity1;
                var item   = entity.e.inventory.items[result.int1];

                mUseParams.Clear();
                mUseParams.map = mGameMap;

                if (mGameState == GameState.SHOW_INVENTORY)
                {
                    entity.e.inventory.UseItem(resultSet, item, mUseParams);
                }
                else if (mGameState == GameState.DROP_INVENTORY)
                {
                    entity.e.inventory.DropItem(resultSet, item);
                }
            }

            break;

            case Result.Type.Consumed:
            {
                var entity = result.entity1;
                var item   = result.entity2;

                entity.e.inventory.RemoveItem(resultSet, item);

                tookTurn = true;
            }

            break;

            case Result.Type.DropInventory:
                if (mGameState != GameState.DROP_INVENTORY)
                {
                    ChangeState(GameState.DROP_INVENTORY);
                }
                else
                {
                    ChangeState(mPreviousGameState);
                }

                break;

            case Result.Type.ItemDropped:
                result.entity1.e.renderOrder = RenderFunctions.RenderOrder.ITEM;
                tookTurn = true;

                RB.SoundPlay(game.assets.soundInventory, 1, RandomUtils.RandomPitch(0.1f));
                break;

            case Result.Type.Equip:
            {
                var equipper = result.entity1;
                var item     = result.entity2;

                if (equipper.e == null || equipper.e.equipment == null || item.e == null || item.e.equippable == null)
                {
                    break;
                }

                equipper.e.equipment.ToggleEquip(resultSet, item);
            }

            break;

            case Result.Type.Equipped:
            {
                var equipper = result.entity1;
                var item     = result.entity2;

                if (equipper.e == null || equipper.e.equipment == null || item.e == null || item.e.equippable == null)
                {
                    break;
                }

                RB.SoundPlay(game.assets.soundInventory, 1, RandomUtils.RandomPitch(0.1f));
            }

            break;

            case Result.Type.Dequipped:
            {
                var equipper = result.entity1;
                var item     = result.entity2;

                if (equipper.e == null || equipper.e.equipment == null || item.e == null || item.e.equippable == null)
                {
                    break;
                }

                RB.SoundPlay(game.assets.soundInventory, 1, RandomUtils.RandomPitch(0.1f));
            }

            break;

            case Result.Type.Targeting:
                // Set previous state to players turn to go back to players turn if targeting is cancelled
                mPreviousGameState = GameState.PLAYER_TURN;
                ChangeState(GameState.TARGETING);
                mTargetingItem = result.entity1;

                mConsole.Log(mTargetingItem.e.item.targetingMessage);
                break;

            case Result.Type.LeftClick:
            {
                if (mGameState == GameState.TARGETING && !mTargetingItem.isEmpty)
                {
                    var targetingPos = result.veci1;

                    if (mTargetingItem.e.equippable != null && mTargetingItem.e.equippable.slot == EquipmentSlot.Ranged)
                    {
                        var arrow = mPlayer.e.inventory.GetArrow();
                        if (SkillFunctions.ShootBow(resultSet, mPlayer, arrow, mTargetingItem.e.item.int2, mTargetingItem.e.item.int1, targetingPos))
                        {
                            mPlayer.e.inventory.RemoveItem(resultSet, arrow);
                            EntityStore.DestroyEntity(arrow);
                        }

                        ChangeState(GameState.ENEMY_TURN);
                    }
                    else
                    {
                        mUseParams.Clear();
                        mUseParams.map   = mGameMap;
                        mUseParams.veci1 = targetingPos;
                        mUseParams.bool1 = true;

                        mPlayer.e.inventory.UseItem(resultSet, mTargetingItem, mUseParams);
                    }
                }
            }

            break;

            case Result.Type.RightClick:
                if (mGameState == GameState.TARGETING)
                {
                    resultSet.AddTargetingCancelled();
                }

                break;

            case Result.Type.TargetingCancelled:
                ChangeState(GameState.PLAYER_TURN);
                mTargetingItem = EntityID.empty;
                mConsole.Log(C.FSTR.Set("Targeting cancelled."));
                break;

            case Result.Type.ShowHelp:
                if (mGameState != GameState.SHOW_HELP)
                {
                    ChangeState(GameState.SHOW_HELP);
                }
                else
                {
                    ChangeState(mPreviousGameState);
                }

                break;

            case Result.Type.TakeStairs:
            {
                int  i;
                bool foundStairs = false;

                var entityList = EntityFunctions.GetEntitiesAtPos(mPlayer.e.pos);
                if (entityList != null)
                {
                    for (i = 0; i < entityList.Count; i++)
                    {
                        var e = entityList[i].e;
                        if (e.stairs != null && e.stairs.type != Stairs.StairType.WELL_CLOSED)
                        {
                            EffectManager.Instance.Clear();

                            mGameMap.NextFloor(resultSet, mPlayer, mConsole);
                            mFOVRecompute   = true;
                            mFloodRecompute = true;

                            // Snap the camera to player
                            mCamera.SetPos(mPlayer);

                            foundStairs = true;

                            if (e.stairs.type == Stairs.StairType.STAIRS)
                            {
                                RB.SoundPlay(game.assets.soundStairs);

                                mPlayer.e.fighter.Heal(resultSet, mPlayer.e.fighter.maxHp / 2);
                                mConsole.Log(C.FSTR.Set("You take a moment to rest, and recover your strength."));
                            }
                            else if (e.stairs.type == Stairs.StairType.PORTAL)
                            {
                                RB.SoundPlay(game.assets.soundPortal);
                                mPlayer.e.fighter.Heal(resultSet, mPlayer.e.fighter.maxHp / 2);
                                mConsole.Log(C.FSTR.Set("You step into the mysterious portal..."));
                            }
                            else if (e.stairs.type == Stairs.StairType.WELL)
                            {
                                RB.SoundPlay(game.assets.soundJump);
                                mConsole.Log(C.FSTR.Set("You jump down the well into the darkness below..."));
                            }

                            if (mCurrentMusic != mGameMap.music)
                            {
                                RB.MusicPlay(mGameMap.music);
                                mCurrentMusic = mGameMap.music;
                            }

                            // Save the game after descending
                            DataLoaders.SaveGame(C.SAVE_FILENAME, mPlayer, mGameMap, mConsole, mGameState);

                            break;
                        }
                        else if (e.stairs != null && e.stairs.type == Stairs.StairType.WELL_CLOSED)
                        {
                            foundStairs = true;

                            mConsole.Log(C.FSTR.Set("You look down the well. That won't be necessary, not this time..."));
                        }
                    }
                }

                if (!foundStairs)
                {
                    mConsole.Log(C.FSTR.Set("There are no stairs here."));
                }
            }

            break;

            case Result.Type.Xp:
                int xp        = result.int1;
                var leveledUp = mPlayer.e.level.AddXp(xp);
                mConsole.Log(C.FSTR.Set("You gain ").Append(xp).Append(" experience points."));

                if (leveledUp)
                {
                    mConsole.Log(C.FSTR.Set("Your battle skills grow stronger! You reached level ").Append(mPlayer.e.level.currentLevel).Append("!"));
                    mPreviousGameState = mGameState;
                    ChangeState(GameState.LEVEL_UP);

                    mMenuLevelUp.ClearOptions();
                    mMenuLevelUp.AddOption(C.FSTR.Set("Constitution (+20 HP, from ").Append(mPlayer.e.fighter.maxHp).Append(")"));
                    mMenuLevelUp.AddOption(C.FSTR.Set("Strength (+1 attack, from ").Append(mPlayer.e.fighter.power).Append(")"));
                    mMenuLevelUp.AddOption(C.FSTR.Set("Agility (+1 defense, from ").Append(mPlayer.e.fighter.defense).Append(")"));

                    RB.SoundPlay(game.assets.soundLevelUp);
                }

                break;

            case Result.Type.LevelUp:
                var levelUp = (LevelUp)result.int1;

                switch (levelUp)
                {
                case LevelUp.Hp:
                    mPlayer.e.fighter.baseMaxHp += 20;
                    mPlayer.e.fighter.hp        += 20;
                    break;

                case LevelUp.Str:
                    mPlayer.e.fighter.basePower += 1;
                    break;

                case LevelUp.Def:
                    mPlayer.e.fighter.baseDefense += 1;
                    break;
                }

                mGameState = mPreviousGameState;

                break;

            case Result.Type.ShowCharacterScreen:
                mPreviousGameState = mGameState;
                ChangeState(GameState.CHARACTER_SCREEN);

                C.FSTR.Clear();
                C.FSTR.Append("@FFFFFFLevel: ").Append(C.STR_COLOR_NAME).Append(mPlayer.e.level.currentLevel).Append("\n");
                C.FSTR.Append("@FFFFFFExperience: ").Append(C.STR_COLOR_NAME).Append(mPlayer.e.level.currentXp).Append("\n");
                C.FSTR.Append("@FFFFFFExperience to Level: ").Append(C.STR_COLOR_NAME).Append(mPlayer.e.level.ExperienceToNextLevel()).Append("\n");
                C.FSTR.Append("@FFFFFFMaximum HP: ").Append(C.STR_COLOR_NAME).Append(mPlayer.e.fighter.maxHp).Append("\n");
                C.FSTR.Append("@FFFFFFAttack: ").Append(C.STR_COLOR_NAME).Append(mPlayer.e.fighter.power).Append("\n");
                C.FSTR.Append("@FFFFFFDefense: ").Append(C.STR_COLOR_NAME).Append(mPlayer.e.fighter.defense);
                mMenuCharacterScreen.SetSummary(C.FSTR);

                break;

            case Result.Type.BossDefeated:
                var boss = result.entity1;
                map.SpawnExitPortal(boss.e.pos);
                break;

            case Result.Type.GameWon:
            {
                var options = new List <SceneMessage.MessageBoxOption>();
                options.Add(new SceneMessage.MessageBoxOption(C.FSTR.Set("Return to Main Menu"), CloseGameWonMessageBox));

                C.FSTR.Set(C.STR_COLOR_DIALOG);
                C.FSTR.Append("You make it out of the forest clearing with adrenaline still pumping through your veins.");
                C.FSTR.Append("\n\n");
                C.FSTR.Append("Your adventure flashes through your mind and you realize you're not the same person you were before. ");
                C.FSTR.Append("The concerns you once had seem insignificant now.");
                C.FSTR.Append("\n\n");
                C.FSTR.Append("Moments later you calm down, and you find yourself wondering what lies at the bottom of other old wells...");
                C.FSTR.Append("\n\n");
                C.FSTR.Append(C.STR_COLOR_NAME);
                C.FSTR.Append("You've won!\nCongratulations!");

                game.ShowMessageBox(
                    C.FSTR2.Set("A New Life"),
                    C.FSTR,
                    options);
                break;
            }

            case Result.Type.FellDownWell:
            {
                var options = new List <SceneMessage.MessageBoxOption>();
                options.Add(new SceneMessage.MessageBoxOption(C.FSTR.Set("Continue"), CloseMessageBox));

                C.FSTR.Set(C.STR_COLOR_DIALOG);
                C.FSTR.Append("This is not what you expected. It seems that not only has the bottom of this well ran dry, it has collapsed into some old dungeon! ");
                C.FSTR.Append("There must be some way out of this place, there has to be.");
                C.FSTR.Append("\n\n");
                C.FSTR.Append("A sound of skittering creatures can be heard coming from the nearby rooms. ");
                C.FSTR.Append("You spot a rusty dagger lying beside you.");
                C.FSTR.Append("\n\n");
                C.FSTR.Append("Finding an exit may prove... difficult.");

                game.ShowMessageBox(
                    C.FSTR2.Set("Bottom of the Well"),
                    C.FSTR,
                    options);
                break;
            }

            case Result.Type.BossEncounter:
            {
                var options = new List <SceneMessage.MessageBoxOption>();
                options.Add(new SceneMessage.MessageBoxOption(C.FSTR.Set("Continue"), CloseMessageBox));

                C.FSTR.Set(C.STR_COLOR_DIALOG);
                C.FSTR.Append("Before you stands a towering golem. It lurches forward, slowly at first, as if it has not moved in ages.");
                C.FSTR.Append("\n\n");
                C.FSTR.Append(C.STR_COLOR_NAME);
                C.FSTR.Append("\"Who awakens the Gatekeeper?\"").Append(C.STR_COLOR_DIALOG).Append(" it belows.");
                C.FSTR.Append("\n\n");
                C.FSTR.Append("A Gatekeeper is just what you were looking for. This is your chance to escape the dungeon! You steady yourself, this will not be an easy fight.");

                game.ShowMessageBox(
                    C.FSTR2.Set("The Gatekeeper"),
                    C.FSTR,
                    options);
                break;
            }
            }
        }
Пример #6
0
        /// <summary>
        /// Cast fireball
        /// </summary>
        /// <param name="resultSet">Result set</param>
        /// <param name="caster">Caster</param>
        /// <param name="radius">Radius of explosion</param>
        /// <param name="damage">Damage</param>
        /// <param name="targetPos">Target position</param>
        /// <param name="hurtsCaster">True if explosion should hurt caster</param>
        /// <returns>True if successful</returns>
        public static bool CastFireball(ResultSet resultSet, EntityID caster, int radius, int damage, Vector2i targetPos, bool hurtsCaster)
        {
            var game = (RetroDungeoneerGame)RB.Game;
            var map  = game.map;

            if (!CheckTargetPosValid(resultSet, targetPos, caster))
            {
                return(false);
            }

            resultSet.AddMessage(
                C.FSTR.Set("The fireball explodes, burning everything within ").Append(C.STR_COLOR_NAME).Append(radius).Append("@- tiles!"));

            // Apply damage to all entities in range
            for (int x = targetPos.x - radius; x <= targetPos.x + radius; x++)
            {
                if (x < 0 || x >= map.size.width)
                {
                    continue;
                }

                for (int y = targetPos.y - radius; y <= targetPos.y + radius; y++)
                {
                    if (y < 0 || y >= map.size.height)
                    {
                        continue;
                    }

                    var pos   = new Vector2i(x, y);
                    var delta = pos - targetPos;
                    int dist  = UnityEngine.Mathf.RoundToInt(delta.Magnitude());

                    if (dist > radius)
                    {
                        continue;
                    }

                    var tile = map.terrain[x, y];

                    if (!tile.blocked)
                    {
                        var entities = EntityFunctions.GetEntitiesAtPos(new Vector2i(x, y));

                        for (int i = 0; i < entities.Count; i++)
                        {
                            if (entities[i] == caster && !hurtsCaster)
                            {
                                continue;
                            }

                            var e = entities[i].e;
                            if (e.fighter != null)
                            {
                                int actualDamage = (damage + caster.e.fighter.power) - e.fighter.defense;
                                if (actualDamage == 0)
                                {
                                    actualDamage = 1;
                                }

                                resultSet.AddMessage(
                                    C.FSTR.Set("The ").Append(C.STR_COLOR_NAME).Append(e.name).Append("@- got burned for ").Append(C.STR_COLOR_DAMAGE).Append(actualDamage).Append("@- hit points."));

                                e.fighter.TakeDamage(resultSet, actualDamage);
                            }
                        }

                        EffectManager.Instance.AddEffect(new EffectFlame(pos, dist * 4));
                    }
                }
            }

            RB.SoundPlay(game.assets.soundFireBall);

            return(true);
        }
Пример #7
0
        /// <summary>
        /// Initialize your game here.
        /// </summary>
        /// <returns>Return true if successful</returns>
        public bool Initialize()
        {
            // You can load a spritesheet here
            RB.SpriteSheetSetup(0, "Demos/RetroDungeoneer/SpritePack", new Vector2i(16, 16));
            RB.SpriteSheetSet(0);

            var fontSprite = RB.PackedSpriteGet(S.FONT_RETROBLIT_DROPSHADOW);
            var fontPos    = new Vector2i(fontSprite.SourceRect.x + 1, fontSprite.SourceRect.y + 1);

            RB.FontSetup(C.FONT_RETROBLIT_DROPSHADOW, '!', (char)((int)'~' + 8), fontPos, 0, new Vector2i(6, 7), ((int)'~' + 8) - (int)'!' + 1, 1, 1, false);

            RB.MusicSetup(C.MUSIC_MAIN_MENU, "Demos/RetroDungeoneer/Music/ReturnToNowhere");
            RB.MusicSetup(C.MUSIC_GAME, "Demos/RetroDungeoneer/Music/DungeonAmbience");
            RB.MusicSetup(C.MUSIC_DEATH, "Demos/RetroDungeoneer/Music/DeathPiano");
            RB.MusicSetup(C.MUSIC_FOREST, "Demos/RetroDungeoneer/Music/ForestAmbience");

            RB.SoundSetup(C.SOUND_MONSTER_DEATH, "Demos/RetroDungeoneer/Sounds/MonsterDeath");
            RB.SoundSetup(C.SOUND_PLAYER_DEATH, "Demos/RetroDungeoneer/Sounds/PlayerDeath");
            RB.SoundSetup(C.SOUND_FOOT_STEP, "Demos/RetroDungeoneer/Sounds/FootStep");
            RB.SoundSetup(C.SOUND_MONSTER_ATTACK, "Demos/RetroDungeoneer/Sounds/MonsterAttack");
            RB.SoundSetup(C.SOUND_PLAYER_ATTACK, "Demos/RetroDungeoneer/Sounds/PlayerAttack");
            RB.SoundSetup(C.SOUND_INVENTORY, "Demos/RetroDungeoneer/Sounds/Inventory");
            RB.SoundSetup(C.SOUND_DRINK, "Demos/RetroDungeoneer/Sounds/Drink");
            RB.SoundSetup(C.SOUND_MENU_OPEN, "Demos/RetroDungeoneer/Sounds/MenuOpen");
            RB.SoundSetup(C.SOUND_MENU_CLOSE, "Demos/RetroDungeoneer/Sounds/MenuClose");
            RB.SoundSetup(C.SOUND_STAIRS, "Demos/RetroDungeoneer/Sounds/Stairs");
            RB.SoundSetup(C.SOUND_POINTER_SELECT, "Demos/RetroDungeoneer/Sounds/PointerSelect");
            RB.SoundSetup(C.SOUND_SELECT_OPTION, "Demos/RetroDungeoneer/Sounds/SelectOption");
            RB.SoundSetup(C.SOUND_LEVEL_UP, "Demos/RetroDungeoneer/Sounds/LevelUp");
            RB.SoundSetup(C.SOUND_FIREBALL, "Demos/RetroDungeoneer/Sounds/Fireball");
            RB.SoundSetup(C.SOUND_LIGHTNING, "Demos/RetroDungeoneer/Sounds/Lightning");
            RB.SoundSetup(C.SOUND_CONFUSE, "Demos/RetroDungeoneer/Sounds/Confuse");
            RB.SoundSetup(C.SOUND_CHEAT, "Demos/RetroDungeoneer/Sounds/CheatMode");
            RB.SoundSetup(C.SOUND_AGGRO1, "Demos/RetroDungeoneer/Sounds/Aggro1");
            RB.SoundSetup(C.SOUND_AGGRO2, "Demos/RetroDungeoneer/Sounds/Aggro2");
            RB.SoundSetup(C.SOUND_PLAYER_FALL_YELL, "Demos/RetroDungeoneer/Sounds/PlayerFallYell");
            RB.SoundSetup(C.SOUND_PORTAL, "Demos/RetroDungeoneer/Sounds/Portal");
            RB.SoundSetup(C.SOUND_JUMP, "Demos/RetroDungeoneer/Sounds/Jump");
            RB.SoundSetup(C.SOUND_BOW_SHOOT, "Demos/RetroDungeoneer/Sounds/BowShoot");
            RB.SoundSetup(C.SOUND_BOW_HIT, "Demos/RetroDungeoneer/Sounds/BowHit");
            RB.SoundSetup(C.SOUND_WEB, "Demos/RetroDungeoneer/Sounds/Web");
            RB.SoundSetup(C.SOUND_TELEPORT, "Demos/RetroDungeoneer/Sounds/Teleport");
            RB.SoundSetup(C.SOUND_SLIME, "Demos/RetroDungeoneer/Sounds/Slime");

            RB.ShaderSetup(C.SHADER_VIGNETTE, "Demos/RetroDungeoneer/DrawVignette");

            RB.EffectSet(RB.Effect.Scanlines, 0.5f);

            EntityFunctions.Initialize();
            S.InitializeAnims();

            InitializeNewGame.InitializeConstants();

            RenderFunctions.Initialize();

            mSceneGame     = new SceneGame();
            mSceneMainMenu = new SceneMainMenu();
            mSceneMessage  = new SceneMessage();

            // Generate tile grid, this is a one time operation, we can keep reusing the grid
            var gridColor = Color.white;

            for (int x = 0; x < RB.MapSize.width; x++)
            {
                for (int y = 0; y < RB.MapSize.height; y++)
                {
                    RB.MapSpriteSet(C.LAYER_GRID, new Vector2i(x, y), S.GRID, gridColor);
                }
            }

            ChangeScene(SceneEnum.MAIN_MENU);

            // Collect any garbage created during initilization to avoid a performance hiccup later.
            System.GC.Collect();

            return(true);
        }
Пример #8
0
        private void MakeForestMap(int mapWidth, int mapHeight, EntityID player)
        {
            backgroundColor = new Color32(0x25, 0x8f, 0x4a, 255);
            mMusic          = C.MUSIC_FOREST;

            var playerEntity = EntityStore.Get(player);

            if (playerEntity == null)
            {
                return;
            }

            int width  = Random.Range(14, 18);
            int height = Random.Range(14, 18);

            int x = (mapWidth / 2) - (width / 2);
            int y = (mapHeight / 2) - (height / 2);

            var newRoom = new Rect2i(x, y, width, height);

            CreateRoom(newRoom, RoomShape.EllipseFuzzy);

            var roomCenter = newRoom.center;

            int randExit = Random.Range(0, 4);

            Vector2i blockadePos = Vector2i.zero;
            Vector2i thugPos     = Vector2i.zero;
            Vector2i gameExitPos = Vector2i.zero;
            Vector2i gameExitDir = Vector2i.zero;

            if (randExit == 0)
            {
                CreateHTunnel(roomCenter.x, 0, roomCenter.y);
                blockadePos    = new Vector2i(roomCenter.x - (newRoom.width / 2) - 2, roomCenter.y);
                gameExitPos    = blockadePos;
                gameExitPos.x -= 3;
                gameExitDir    = new Vector2i(-1, 0);
                thugPos        = blockadePos;
                thugPos.x     += 4;
            }
            else if (randExit == 1)
            {
                CreateHTunnel(roomCenter.x, mapWidth - 1, roomCenter.y);
                blockadePos    = new Vector2i(roomCenter.x + (newRoom.width / 2) + 2, roomCenter.y);
                gameExitPos    = blockadePos;
                gameExitPos.x += 3;
                gameExitDir    = new Vector2i(1, 0);
                thugPos        = blockadePos;
                thugPos.x     -= 4;
            }
            else if (randExit == 2)
            {
                CreateVTunnel(0, roomCenter.y, roomCenter.x);
                blockadePos    = new Vector2i(roomCenter.x, roomCenter.y - (newRoom.height / 2) - 2);
                gameExitPos    = blockadePos;
                gameExitPos.y -= 3;
                gameExitDir    = new Vector2i(0, -1);
                thugPos        = blockadePos;
                thugPos.y     += 4;
            }
            else if (randExit == 3)
            {
                CreateVTunnel(mapHeight - 1, roomCenter.y, roomCenter.x);
                blockadePos    = new Vector2i(roomCenter.x, roomCenter.y + (newRoom.height / 2) + 2);
                gameExitPos    = blockadePos;
                gameExitPos.y += 3;
                gameExitDir    = new Vector2i(0, 1);
                thugPos        = blockadePos;
                thugPos.y     -= 4;
            }

            // This is the first room, put the player in the center of it
            playerEntity.pos = RandomUtils.RandomRectPerimeterPos(new Rect2i(roomCenter.x - 1, roomCenter.y - 1, 3, 3));

            EntityID thug = EntityID.empty;

            if (dungeonLevel == 0)
            {
                thug = EntityFunctions.CreateMonster(MonsterType.InvincibleThug, thugPos);
                EntityFunctions.CreateMonster(MonsterType.InvincibleBlockade, blockadePos);
            }
            else
            {
                thug = EntityFunctions.CreateMonster(MonsterType.Thug, thugPos);
                EntityFunctions.CreateMonster(MonsterType.Blockade, blockadePos);

                while (gameExitPos.x > 0 && gameExitPos.y > 0 && gameExitPos.x < size.width && gameExitPos.y < size.height)
                {
                    EntityFunctions.CreateInteractable(InteractableType.GameExit, gameExitPos);
                    gameExitPos += gameExitDir;
                }
            }

            // Give thug a dagger and armor
            var dagger = EntityFunctions.CreateItem(ItemType.Dagger, new Vector2i(-1, -1));

            thug.e.inventory = new Inventory(1);
            thug.e.equipment = new Equipment();
            thug.e.equipment.equipment[(int)dagger.e.equippable.slot] = dagger;

            var armor = EntityFunctions.CreateItem(ItemType.LeatherArmor, new Vector2i(-1, -1));

            thug.e.equipment.equipment[(int)armor.e.equippable.slot] = armor;

            var well = EntityFunctions.CreateInteractable(InteractableType.Well, new Vector2i(roomCenter.x, roomCenter.y + 2));

            well.e.stairs = new Stairs(dungeonLevel + 1);
            if (dungeonLevel == 0)
            {
                well.e.stairs.type = Stairs.StairType.WELL;
            }
            else
            {
                well.e.stairs.type = Stairs.StairType.WELL_CLOSED;
            }

            UpdateAllEntityMapPositions();

            BeautifyForestMap();

            RecomputeFov(player, C.FOV_RADIUS);

            var game    = (RetroDungeoneerGame)RB.Game;
            var options = new List <SceneMessage.MessageBoxOption>();

            options.Add(new SceneMessage.MessageBoxOption(C.FSTR.Set("Continue"), CloseMessageBox));

            if (dungeonLevel == 0)
            {
                C.FSTR.Set(C.STR_COLOR_DIALOG);
                C.FSTR.Append("You've been travelling through the forest for hours and decide to rest at a nearby clearing.");
                C.FSTR.Append("\n\n");
                C.FSTR.Append("As you settle down a man appears behind you. He swings his sword at a rope tied to a tree beside him. Branches and debris fall onto the path blocking your only exit. It appears you've been ambushed.");
                C.FSTR.Append("\n\n");
                C.FSTR.Append(C.STR_COLOR_NAME);
                C.FSTR.Append("\"I'll take what you're carrying, once I'm done carving you up!\"").Append(C.STR_COLOR_DIALOG).Append(" the brigand says with a grimace.");
                C.FSTR.Append("\n\n");
                C.FSTR.Append("Your eyes dart to an old well in the middle of the clearing. Your options seem clear... jump down the well, or die here.");

                game.ShowMessageBox(
                    C.FSTR2.Set("Trapped"),
                    C.FSTR,
                    options);
            }
            else
            {
                C.FSTR.Set(C.STR_COLOR_DIALOG);
                C.FSTR.Append("You open your eyes, the swirling portal closes behind you. You find yourself back where it all started, in the forest clearing.");
                C.FSTR.Append("\n\n");
                C.FSTR.Append("The brigand who ambushed you is still here, preparing his trap for the next victim.");
                C.FSTR.Append("\n\n");
                C.FSTR.Append(C.STR_COLOR_NAME);
                C.FSTR.Append("\"How did you... nevermind, lets finish what we started!\"").Append(C.STR_COLOR_DIALOG).Append(" he says, startled by your sudden appearance.");
                C.FSTR.Append("\n\n");
                C.FSTR.Append("You tighten your grip on your weapon, you won't be jumping into the well this time...");

                game.ShowMessageBox(
                    C.FSTR2.Set("A Sudden Return"),
                    C.FSTR,
                    options);
            }
        }
Пример #9
0
        private void MakeDungeonMap(int maxRooms, int roomMinSize, int roomMaxSize, int mapWidth, int mapHeight, EntityID player)
        {
            backgroundColor = new Color32(0x47, 0x2d, 0x3c, 255);
            mMusic          = C.MUSIC_GAME;

            var playerEntity = EntityStore.Get(player);

            if (playerEntity == null)
            {
                return;
            }

            List <Rect2i> rooms = new List <Rect2i>();

            for (int r = 0; r < maxRooms; r++)
            {
                // Random width and height
                int width  = 0;
                int height = 0;

                if (dungeonLevel < 5 || rooms.Count > 0)
                {
                    width  = Random.Range(roomMinSize, roomMaxSize + 1);
                    height = Random.Range(roomMinSize, roomMaxSize + 1);
                }
                else
                {
                    width  = Random.Range(roomMinSize * 2, (roomMaxSize * 2) + 1);
                    height = Random.Range(roomMinSize * 2, (roomMaxSize * 2) + 1);
                }

                // Random position
                int x = Random.Range(0, mapWidth - width);
                int y = Random.Range(0, mapHeight - height);

                var newRoom = new Rect2i(x, y, width, height);

                // Check if the room intersects with other rooms
                bool intersects = false;
                for (int i = 0; i < rooms.Count; i++)
                {
                    if (newRoom.Intersects(rooms[i]))
                    {
                        intersects = true;
                        break;
                    }
                }

                // No intersections, it's safe to create this room
                if (!intersects)
                {
                    CreateRoom(newRoom, RoomShape.Rectangle);

                    var roomCenter = newRoom.center;

                    if (rooms.Count > 0)
                    {
                        // All rooms after the first one should be connected with a tunnel to the previous room
                        var prevRoomCenter = rooms[rooms.Count - 1].center;

                        if (Random.Range(0, 2) == 1)
                        {
                            CreateHTunnel(prevRoomCenter.x, roomCenter.x, prevRoomCenter.y);
                            CreateVTunnel(prevRoomCenter.y, roomCenter.y, roomCenter.x);
                        }
                        else
                        {
                            CreateVTunnel(prevRoomCenter.y, roomCenter.y, prevRoomCenter.x);
                            CreateHTunnel(prevRoomCenter.x, roomCenter.x, roomCenter.y);
                        }
                    }

                    // Add the new room to list of rooms
                    rooms.Add(newRoom);
                }
            }

            // Populate all rooms except for first and last
            for (int i = 1; i < rooms.Count - 1; i++)
            {
                if (i != 0 && i != rooms.Count - 1)
                {
                    var numOfMonsters = RandomUtils.FromDungeonLevel(
                        new RandomUtils.Tuple <int, int>[]
                    {
                        new RandomUtils.Tuple <int, int>(2, 1),
                        new RandomUtils.Tuple <int, int>(3, 3),
                        new RandomUtils.Tuple <int, int>(5, 5)
                    },
                        dungeonLevel);

                    var numOfItems = RandomUtils.FromDungeonLevel(
                        new RandomUtils.Tuple <int, int>[]
                    {
                        new RandomUtils.Tuple <int, int>(1, 1),
                        new RandomUtils.Tuple <int, int>(2, 4)
                    },
                        dungeonLevel);

                    PlaceEntities(rooms[i], numOfItems, numOfMonsters);
                }
            }

            var firstRoom = rooms[0];
            var lastRoom  = rooms[rooms.Count - 1];

            if (dungeonLevel < 5)
            {
                MakeStartRoom(player, firstRoom);
                var stairsDown = EntityFunctions.CreateInteractable(InteractableType.Stairs, lastRoom.center);
                stairsDown.e.stairs = new Stairs(dungeonLevel + 1);
            }
            else
            {
                // For final level make the player start room the last room, and boss room the first room
                // This makes it easier to ensure we can fit a nice big boss room before creating other rooms
                MakeBossRoom(firstRoom);
                MakeStartRoom(player, lastRoom);
            }

            UpdateAllEntityMapPositions();

            BeautifyDungeonMap();

            RecomputeFov(player, C.FOV_RADIUS);

            if (dungeonLevel == 1)
            {
                EffectManager.Instance.AddEffect(new EffectPlayerEntrance(player));
            }
        }
Пример #10
0
        /// <summary>
        /// Make test final boss room
        /// </summary>
        /// <param name="room">Room rect</param>
        public void MakeTestBossRoom(Rect2i room)
        {
            var boss = EntityFunctions.CreateMonster(MonsterType.Golem, new Vector2i(room.center.x, room.center.y - (room.height / 4)));

            boss.e.fighter.hp = 1;
        }
Пример #11
0
 /// <summary>
 /// Make final boss room
 /// </summary>
 /// <param name="room">Room rect</param>
 public void MakeBossRoom(Rect2i room)
 {
     EntityFunctions.CreateMonster(MonsterType.Golem, new Vector2i(room.center.x, room.center.y - (room.height / 4)));
 }
Пример #12
0
        private bool DoSkill(ResultSet resultSet, EntityID target)
        {
            if (mSkills.Count == 0)
            {
                return(false);
            }

            int skillIndex = RandomUtils.RandomChoiceIndex(mSkillChances);

            Skill randomSkill = mSkills[skillIndex];

            // Check if there is a backup melee skill
            bool hasMeleeSkill = false;

            for (int i = 0; i < mSkills.Count; i++)
            {
                if (mSkills[i] == Skill.MeleeAttack)
                {
                    hasMeleeSkill = true;
                    break;
                }
            }

            var game = (RetroDungeoneerGame)RB.Game;

            bool skillResult = false;

            switch (randomSkill)
            {
            case Skill.MeleeAttack:
                return(SkillFunctions.MeleeAttack(resultSet, owner, target));

            case Skill.CastWeb:
                skillResult = SkillFunctions.CastWeb(resultSet, owner, target.e.pos);
                break;

            case Skill.CastLightning:
                skillResult = SkillFunctions.CastLightning(resultSet, owner, target.e.pos, 6, 12);
                break;

            case Skill.ShootBow:
            {
                var arrow = owner.e.inventory.GetArrow();
                if (!arrow.isEmpty)
                {
                    skillResult = SkillFunctions.ShootBow(resultSet, owner, arrow, 6, 10, target.e.pos);
                    if (skillResult)
                    {
                        owner.e.inventory.RemoveItem(null, arrow);
                        EntityStore.DestroyEntity(arrow);
                    }
                }
            }

            break;

            case Skill.CastRandomFireball:
            {
                int attempts = 40;

                while (attempts > 0)
                {
                    var fireballPos = new Vector2i(target.e.pos.x, target.e.pos.y);
                    fireballPos.x += Random.Range(-20, 21);
                    fireballPos.y += Random.Range(-20, 21);

                    if (game.map.IsInFOV(fireballPos))
                    {
                        skillResult = SkillFunctions.CastFireball(resultSet, owner, 4, 10, fireballPos, false);
                        break;
                    }

                    attempts--;
                }
            }

            break;

            case Skill.Teleport:
            {
                // Find a location to teleport on the furthest side of target from where the entity is now
                // Limited attempts are made, so this may not end up being furthest
                var furthestPos  = new Vector2i(-1, -1);
                var furthestDist = 0.0f;

                int      attempts  = 40;
                Vector2i targetPos = target.e.pos;

                while (attempts > 0)
                {
                    var randomPos = new Vector2i(Random.Range(targetPos.x - 1, targetPos.x + 2), Random.Range(targetPos.y - 1, targetPos.y + 2));

                    if (EntityFunctions.GetBlockingEntityAtPos(randomPos).isEmpty&& !game.map.IsBlocked(randomPos))
                    {
                        float dist = (owner.e.pos - randomPos).SqrMagnitude();
                        if (dist > furthestDist)
                        {
                            furthestDist = dist;
                            furthestPos  = randomPos;
                        }
                    }

                    attempts--;
                }

                if (furthestPos.x != -1)
                {
                    skillResult = SkillFunctions.Teleport(resultSet, owner, furthestPos);
                }
                else
                {
                    Debug.Log("Failed");
                }
            }

            break;
            }

            if (skillResult == false && hasMeleeSkill)
            {
                skillResult = SkillFunctions.MeleeAttack(resultSet, owner, target);
            }

            return(skillResult);
        }
Пример #13
0
        /// <summary>
        /// Refresh the floodmap, from the given origin
        /// </summary>
        /// <param name="origin">Origin position</param>
        /// <param name="maxDist">Maximum distance</param>
        public void Refresh(Vector2i origin, int maxDist)
        {
            var game = (RetroDungeoneerGame)RB.Game;

            // Square the distance so we can use squared distance comparison
            // instead of having to use square root
            maxDist = maxDist * maxDist;

            // Reset all costs to max
            for (int i = 0; i < mCosts.Length; i++)
            {
                mCosts[i] = int.MaxValue;
            }

            // Set cost at origin to 0
            mCosts[origin.x + (origin.y * mSize.width)] = 0;
            int count = 0;

            mSearchNodes[count] = origin.x + (origin.y * mSize.width);
            count++;

            int firstNode = 0;
            int lastNode  = 0;

            while (count > 0)
            {
                int i = mSearchNodes[firstNode];
                firstNode++;
                count--;

                int cost = mCosts[i];

                var pos = new Vector2i(i % mSize.width, i / mSize.width);

                // Expand flood into all cardinal directions.
                for (int d = 0; d < Direction.Cardinal.Length; d++)
                {
                    var dir     = Direction.Cardinal[d];
                    int newCost = cost + CARDINAL_COST;

                    var dest            = pos + dir;
                    var deltaFromOrigin = origin - dest;

                    if (!EntityFunctions.GetBlockingEntityAtPos(dest).isEmpty)
                    {
                        newCost += ENTITY_COST;
                    }

                    if (!game.map.IsBlocked(dest) && deltaFromOrigin.SqrMagnitude() <= maxDist)
                    {
                        int j = dest.x + (dest.y * mSize.width);
                        if (mCosts[j] > newCost)
                        {
                            mCosts[j] = newCost;
                            mSearchNodes[lastNode + 1] = j;
                            lastNode++;
                            count++;
                        }
                    }
                }

                // Expand flood into all diagonal directions.
                for (int d = 0; d < Direction.Diagonal.Length; d++)
                {
                    var dir = Direction.Diagonal[d];

                    int newCost = cost + DIAGONAL_COST;

                    var dest            = pos + dir;
                    var deltaFromOrigin = origin - dest;

                    if (!EntityFunctions.GetBlockingEntityAtPos(dest).isEmpty)
                    {
                        newCost += ENTITY_COST;
                    }

                    if (!game.map.IsBlocked(dest) && deltaFromOrigin.SqrMagnitude() <= maxDist)
                    {
                        int j = dest.x + (dest.y * mSize.width);
                        if (mCosts[j] > newCost)
                        {
                            mCosts[j] = newCost;
                            mSearchNodes[lastNode + 1] = j;
                            lastNode++;
                            count++;
                        }
                    }
                }
            }
        }