Exemple #1
0
 public void Use(World world)
 {
     world.AddObject(new Drone(), world.Player.Position);
 }
Exemple #2
0
        //Place a level block in a level. The preferred walls can be specified. These can only be guaranteed
        // if the level has the wall type (for example, preferLeftWall can be ignored if HasLeftWall is false).
        //If a wall isn't preferred at a position, an exit is used instead if Has*Exit is true.
        public void Place(World world, Dictionary<char, ISpecialTileDefinition> specialTiles, int x, int y, bool preferLeftWall = true,
            bool preferRightWall = true, bool preferTopWall = true, bool preferBottomWall = true, bool isBottomOfRoom = false, int numberOfEnemies = 0,
            List<Type> possibleEnemyTypes = null)
        {
            possibleEnemyTypes = possibleEnemyTypes ?? new List<Type>();

            int BlockID = random.Next(int.MaxValue);

            bool[,] isActuallyEmpty = new bool[Width, Height];
            bool[,] isActuallyWall = new bool[Width, Height];
            FairRandomCollection<Vector2> possibleEnemyPositions = new FairRandomCollection<Vector2>();
            FairRandomCollection<Vector2> possibleTurretPositions = new FairRandomCollection<Vector2>();

            //Place the tiles in the level
            for (int i = 0; i < Width; i++)
            {
                for (int j = 0; j < Height; j++)
                {
                    char data = Data[i, j];

                    //Check special tiles until we find a normal tile.
                    int loopCount = 0;

                    //Some tiles can be turned into walls if they end up on the sides of the level.
                    bool specialTileTurnsIntoWallOnSides = false;

                    while (specialTiles.ContainsKey(data))
                    {
                        specialTileTurnsIntoWallOnSides = specialTileTurnsIntoWallOnSides || specialTiles[data].CanBeWall;
                        List<string> specialKeywords = new List<string>(); //Contains the special keywords that are true at this moment.

                        if (preferLeftWall) specialKeywords.Add("LEFTWALL");
                        if (preferRightWall) specialKeywords.Add("RIGHTWALL");
                        if (preferTopWall) specialKeywords.Add("TOPWALL");
                        if (preferBottomWall) specialKeywords.Add("BOTTOMWALL");

                        data = specialTiles[data].GetTile(BlockID, specialKeywords);

                        if (loopCount > 1000)
                            throw new Exception("Possible infinite loop detected! Please change the level definition file.");
                    }

                    //If the special tile can be turned into a wall, check if this should happen.
                    if (specialTileTurnsIntoWallOnSides)
                    {
                        if (i == 0) //Left wall
                        {
                            if (preferLeftWall)
                                data = '1';
                        }
                        if (i == Width - 1) //Right wall
                        {
                            if (preferRightWall)
                                data = '1';
                        }
                        if (j == 0) //Top wall
                        {
                            if (preferTopWall)
                                data = '1';
                        }
                        if (j == Height - 1) //Bottom wall
                        {
                            if (preferBottomWall)
                                data = '1';
                        }
                    }

                    int baseX = x + World.TileWidth * i, baseY = y + World.TileHeight * j;
                    float centerX = baseX + World.TileWidth / 2, centerY = baseY + World.TileHeight / 2;
                    Rectangle stdCollisionRect = new Rectangle(baseX, baseY, World.TileWidth, World.TileHeight);

                    //If it's nothing or something the player can move through, and the bottom of the room, then add a jumpthrough.
                    if (data == '.' | data == '/' | data == '\\' && j == Height - 1 && isBottomOfRoom)
                        world.AddObject(new JumpThrough(new Rectangle(baseX, baseY, World.TileWidth, 1)));

                    if (data == '1') //A wall
                    {
                        world.AddObject(new Wall(stdCollisionRect));

                        isActuallyWall[i, j] = true;
                        if (j != 0 && isActuallyEmpty[i, j - 1])
                        {
                            //We can place an enemy here!
                            possibleEnemyPositions.Add(new Vector2(centerX, centerY - World.TileHeight + 10));
                        }
                    }
                    else if (data == 'T') //A tile
                        world.AddObject(new WindowTile(stdCollisionRect));
                    else if (data == 'D') //A gun door
                        world.AddObject(new GunDoor(), baseX + World.TileWidth / 2, baseY);
                    else if (data == 'M') //A melee door
                        world.AddObject(new MeleeDoor(), baseX + World.TileWidth / 2, baseY);
                    else if (data == 'C') //A rocket door
                        world.AddObject(new RocketDoor(), baseX + World.TileWidth / 2, baseY);
                    else if (data == 'B') //A boss door
                        world.AddObject(new BossDoor(), baseX + World.TileWidth / 2, baseY);
                    else if (data == 'O')
                        world.AddObject(new Portal(), baseX + 6, baseY);
                    else if (data == 'S') //Spikes
                        world.AddObject(new Spikes(), baseX, baseY + (int)(World.TileHeight * (100f / 128f)));
                    else if (data == 'G') //A gun pickup block
                        world.AddObject(new GunPickup(), centerX, centerY);
                    else if (data == 'U') //A gun upgrade pickup block
                        world.AddObject(new GunUpgrade(), centerX, centerY);
                    else if (data == 'W') //A wrench pickup block
                        world.AddObject(new WrenchPickup(), centerX, centerY);
                    else if (data == 'R') //A rocket pickup block
                        world.AddObject(new RocketPickup(), centerX, centerY);
                    else if (data == 'H') //A health pickup block
                        world.AddObject(new HealthDrop(10), centerX, centerY);
                    else if (data == 'A') //First health upgrade
                        world.AddObject(new MaxHPUpgrade(), centerX, centerY);
                    else if (data == 'E') //Huge health upgrade
                        world.AddObject(new HugeMaxHPUpgrade(), centerX, centerY);
                    else if (data == 'F') //Drone upgrade
                        world.AddObject(new DroneRangeUpgrade(), centerX, centerY);
                    else if (data == 'P') //The player
                    {
                        world.Player = new Player();
                        world.AddObject(world.Player, centerX, centerY);
                    }
                    else if (data == 'J') //A jumpthrough block
                        world.AddObject(new JumpThrough(new Rectangle(baseX, baseY, World.TileWidth, 1)));
                    else if (data == '\\') //A slope
                        world.AddObject(new SlopeLeft(stdCollisionRect));
                    else if (data == '/') //A slope
                        world.AddObject(new SlopeRight(stdCollisionRect));
                    else if (data == '.')
                    {
                        //Nothing
                        isActuallyEmpty[i, j] = true;

                        if (j != 0 && isActuallyWall[i, j - 1])
                        {
                            //We can place a turret here!
                            possibleTurretPositions.Add(new Vector2(centerX, baseY + 15));
                        }
                    }
                }
            }

            //Place some enemies.
            for (int i = 0; i < numberOfEnemies; i++)
            {
                if (possibleEnemyTypes.Contains(typeof(Turret)) && World.Random.Next(3) == 0)
                {
                    if (possibleTurretPositions.Count != 0)
                        world.AddObject(new Turret(), possibleTurretPositions.Get());
                }
                else if (possibleEnemyPositions.Count != 0)
                {
                    world.AddObject(Activator.CreateInstance(possibleEnemyTypes.Except(new List<Type>() { typeof(Turret) }).ToList().GetRandomItem())
                        as GameObject, possibleEnemyPositions.Get());
                }
            }
        }
Exemple #3
0
        public void Generate(World world)
        {
            string[] areaBorderNameRight = { "SecondRightBorder", "ThirdRightBorder" }; //The names of area borders.
            string[] areaBorderNameLeft = { "SecondLeftBorder", "ThirdLeftBorder" };

            //Enemy types for each area
            List<List<Type>> enemyTypes = new List<List<Type>>();
            enemyTypes.Add(new List<Type>() { typeof(SlimeMonster), typeof(MeleeMonster) });
            enemyTypes.Add(new List<Type>() { typeof(SlimeMonster), typeof(ShootingMonster), typeof(MeleeMonster), typeof(Turret) });
            enemyTypes.Add(new List<Type>() { typeof(ShootingMonster), typeof(MeleeMonster), typeof(Turret) });

            //The first part of the second area has no turrets yet.
            List<Type> enemyTypesStartSecondArea = new List<Type>() { typeof(SlimeMonster), typeof(ShootingMonster), typeof(MeleeMonster) };

            //Define and initialize variables
            bool[,] isRoom = new bool[WorldWidth, WorldHeight]; //Whether this is a room.
            int[,] area = new int[WorldWidth, WorldHeight]; //The area (for example, 0 for the starting area)
            string[,] theme = new string[WorldWidth, WorldHeight]; //The general appearance.
            bool[,] CanHaveRightExit = new bool[WorldWidth, WorldHeight]; //Whether this room can potentially have a right exit.
            bool[,] CanHaveBottomExit = new bool[WorldWidth, WorldHeight]; //Whether this room can potentially have a right exit.
            List<RoomExit>[,] roomExits = new List<RoomExit>[WorldWidth, WorldHeight];
            List<string>[,] guaranteedSpecialBlocks = new List<string>[WorldWidth, WorldHeight]; //Guaranteed blocks.
            int[,] enemies = new int[WorldWidth, WorldHeight];
            for (int i = 0; i < WorldWidth; i++)
                for (int j = 0; j < WorldHeight; j++)
                {
                    roomExits[i, j] = new List<RoomExit>();
                    guaranteedSpecialBlocks[i, j] = new List<string>();
                    isRoom[i, j] = false;
                    area[i, j] = 0;
                    theme[i, j] = "";
                    CanHaveRightExit[i, j] = true;
                    CanHaveBottomExit[i, j] = true;
                    enemies[i, j] = 0;
                }

            //Your own position and the position of the boss.
            int startingY = WorldHeight / 2 + World.Random.Next(-1, 1);
            int bossY = WorldHeight / 2 + World.Random.Next(-1, 1);

            isRoom[0, startingY] = true; //Starting room
            guaranteedSpecialBlocks[0, startingY].Add("PlayerStart");

            isRoom[1, startingY] = true; //Room right of starting room.
            guaranteedSpecialBlocks[1, startingY].Add("GunPickup");
            guaranteedSpecialBlocks[1, startingY].Add(areaBorderNameRight[0]);

            //Other rooms (main areas).
            int areaTwoBorderStart = 3, areaThreeBorderStart = 5;
            for (int i = 2; i < WorldWidth; i++)
                for (int j = 0; j < WorldHeight; j++)
                {
                    bool isTopOrBottomArea = j == 0 || j == WorldHeight - 1;
                    isRoom[i, j] = true;

                    //Set the area
                    if (i >= areaThreeBorderStart + World.Random.Next(2) - (isTopOrBottomArea ? 1 : 0))
                        area[i, j] = 2;
                    else if (i >= areaTwoBorderStart + World.Random.Next(2) - (isTopOrBottomArea ? 1 : 0))
                        area[i, j] = 1;
                    else
                        area[i, j] = 0;

                    //Set the theme
                    if (World.Random.Next(100) < (isTopOrBottomArea ? 60 : 20)) //Generate cramped rooms. There are more of 'em at the top and bottom.
                        theme[i, j] = "Cramped";
                    else if (World.Random.Next(100) < 20) //Generate an open room
                        theme[i, j] = "Open";
                    else if (area[i, j] == 2 && World.Random.Next(100) < 50) //Generate a room with lots of spikes
                        theme[i, j] = "Spiky";
                    else if (World.Random.Next(100) < 10) //Create a room with windows
                        theme[i, j] = "Windowed";

                    //These areas have a normal amount of enemies, with more enemies in later areas.
                    if (area[i, j] == 0)
                        enemies[i, j] = World.Random.Next(2, 3);
                    else
                        enemies[i, j] = World.Random.Next(3, 6) + area[i, j];
                }

            //There should only be one enemy in the third room.
            enemies[2, startingY] = 1;

            //Add a wrench pickup and a rocket pickup. The rocket pickup should have some distance from the starting area.
            int wrenchPos, rocketPos;
            do
            {
                wrenchPos = World.Random.Next(1, WorldHeight - 1);
            }
            while (Math.Abs(wrenchPos - startingY) < 1);

            if (World.Random.Next(2) == 0)
                rocketPos = 0;
            else
                rocketPos = WorldHeight - 1;

            guaranteedSpecialBlocks[areaTwoBorderStart + 1, wrenchPos].Add("WrenchPickup");
            guaranteedSpecialBlocks[areaThreeBorderStart + 1, rocketPos].Add("RocketPickup");

            //Other rooms (secondary areas)
            for (int i = 0; i < 2; i++)
                for (int j = 0; j < WorldHeight; j++)
                {
                    if (j != startingY)
                    {
                        isRoom[i, j] = true;
                        area[i, j] = 2;
                        CanHaveBottomExit[i, j] = false;

                        //Set if we need a right exit.
                        if ((j == startingY - 1 || j == startingY + 1) && i == 0)
                            CanHaveRightExit[i, j] = true;
                        else if ((j == 0 || j == WorldHeight - 1) && i == 1)
                            CanHaveRightExit[i, j] = true;
                        else
                            CanHaveRightExit[i, j] = false;

                        //And do the same for the bottom exit.
                        if (j != startingY - 1)
                            CanHaveBottomExit[i, j] = true;
                        else
                            CanHaveBottomExit[i, j] = false;

                        //These areas often have lots of enemies
                        enemies[i, j] = World.Random.Next(6, 10);
                    }
                }

            //Add three max health upgrades somewhere
            guaranteedSpecialBlocks[World.Random.Next(3, WorldWidth - 1), World.Random.Next(0, WorldHeight - 1)].Add("MaxHPDropPickup");
            guaranteedSpecialBlocks[WorldWidth - 1, World.Random.Next(bossY)].Add("MaxHPDropPickup");
            guaranteedSpecialBlocks[WorldWidth - 1, World.Random.Next(bossY + 1, WorldHeight)].Add("MaxHPDropPickup");

            //Add the special bonus gun upgrade
            guaranteedSpecialBlocks[0, 0].Add("GunUpgradePickup");

            //Add the huge health upgrade
            guaranteedSpecialBlocks[0, WorldHeight - 1].Add("HugeMaxHPDropPickup");

            //And the drone upgrade
            guaranteedSpecialBlocks[1, WorldHeight - 1].Add("DroneUpgradePickup");

            //Add the boss room.
            CanHaveBottomExit[WorldWidth - 1, bossY - 1] = false; //The room above can't have a bottom exit.
            CanHaveBottomExit[WorldWidth - 1, bossY] = false; //The boss room can't have a bottom exit.
            enemies[WorldWidth - 1, bossY] = 0; //The boss room has no normal enemy spawns
            theme[WorldWidth - 1, bossY] = "Boss"; //The theme is "boss"
            //Add a right exit to it.
            roomExits[WorldWidth - 1, bossY].Add(new RoomExit(new Point(LevelWidth / LevelGenerator.BlockWidth - 1, LevelHeight / LevelGenerator.BlockHeight - 1), Direction.Right));
            guaranteedSpecialBlocks[WorldWidth - 1, bossY].Add("LeftBossDoorBorder");
            guaranteedSpecialBlocks[WorldWidth - 1, bossY].Add("RightBossDoorBorder");
            guaranteedSpecialBlocks[WorldWidth - 1, bossY].Add("BossPortal");
            //Add nine "normal tiles"
            for (int i = 0; i < 9; i++)
                guaranteedSpecialBlocks[WorldWidth - 1, bossY].Add("NormalBossRoomTile");
            guaranteedSpecialBlocks[WorldWidth - 2, bossY].Add("RightRocketBorder");  //Add a border so players must have the rocket launcher.

            //Place the exits
            for (int i = 0; i < WorldWidth; i++)
                for (int j = 0; j < WorldHeight; j++)
                {
                    //Place exits.
                    if (i < WorldWidth - 1 && isRoom[i, j] && isRoom[i + 1, j] && CanHaveRightExit[i, j])
                    {
                        int nextY;
                        if (j == bossY && i == WorldWidth - 2)
                            nextY = LevelHeight / LevelGenerator.BlockHeight - 1;
                        else
                            nextY = World.Random.Next(LevelHeight / LevelGenerator.BlockHeight);
                        roomExits[i, j].Add(new RoomExit(new Point(LevelWidth / LevelGenerator.BlockWidth - 1, nextY), Direction.Right));
                        roomExits[i + 1, j].Add(new RoomExit(new Point(0, nextY), Direction.Left));

                        if (area[i, j] < area[i + 1, j])
                            guaranteedSpecialBlocks[i, j].Add(areaBorderNameRight[area[i + 1, j] - 1]);
                        else if (area[i, j] > area[i + 1, j])
                            guaranteedSpecialBlocks[i + 1, j].Add(areaBorderNameLeft[area[i, j] - 1]);
                    }
                    if (j < WorldHeight - 1 && isRoom[i, j] && isRoom[i, j + 1] && CanHaveBottomExit[i, j] && (area[i, j] == area[i, j + 1]))
                    {
                        int nextX = World.Random.Next(LevelWidth / LevelGenerator.BlockWidth);
                        roomExits[i, j].Add(new RoomExit(new Point(nextX, LevelHeight / LevelGenerator.BlockHeight - 1), Direction.Down));
                        roomExits[i, j + 1].Add(new RoomExit(new Point(nextX, 0), Direction.Up));
                    }
                }

            //And generate the levels.
            for (int i = 0; i < WorldWidth; i++)
                for (int j = 0; j < WorldHeight; j++)
                {
                    List<Type> levelEnemyTypes = enemyTypes[area[i, j]];
                    if (i == 3 && area[i, j] == 1)
                        levelEnemyTypes = enemyTypesStartSecondArea;

                    if (isRoom[i, j])
                        levelGenerator.Generate(world, new Vector2(LevelWidth * World.TileWidth * i, LevelHeight * World.TileHeight * j), roomExits[i, j],
                            guaranteedSpecialBlocks[i, j], theme[i, j], enemies[i, j], levelEnemyTypes);
                }

            //Add the "hack this game" object
            world.AddObject(new HackThisGame());

            //Add the map object
            world.AddObject(new Map());

            //Add the GUI object
            world.AddObject(new GUI());

            //Autotile the world.
            Autotile(world);
        }