/* * Unleashed Pixel Dungeon * Copyright (C) 2015 David Mitchell * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/> */ package com.shatteredpixel.pixeldungeonunleashed.levels; import com.shatteredpixel.pixeldungeonunleashed.Assets; import com.shatteredpixel.pixeldungeonunleashed.Dungeon; import com.shatteredpixel.pixeldungeonunleashed.actors.buffs.Buff; import com.shatteredpixel.pixeldungeonunleashed.actors.mobs.Bestiary; import com.shatteredpixel.pixeldungeonunleashed.actors.mobs.Mob; import com.shatteredpixel.pixeldungeonunleashed.actors.mobs.Necromancer; import com.shatteredpixel.pixeldungeonunleashed.items.Generator; import com.shatteredpixel.pixeldungeonunleashed.items.Heap; import com.shatteredpixel.pixeldungeonunleashed.items.rings.RingOfWealth; import com.shatteredpixel.pixeldungeonunleashed.levels.painters.Painter; import com.watabou.noosa.Scene; import com.watabou.utils.Random; public class OpenLevel extends Level { private int THEME = (Dungeon.depth / 6) % 6; { switch (THEME) { case 0: // this is a sewer level color1 = 0x48763c; color2 = 0x59994a; break; case 1: // this is a prison level color1 = 0x6a723d; color2 = 0x88924c; break; case 2: // this is a caves level color1 = 0x534f3e; color2 = 0xb9d661; break; case 3: // this is a city level color1 = 0x4b6636; color2 = 0xf2f2f2; break; case 4: // this is a frozen level color1 = 0x484876; color2 = 0x4b5999; break; default: // this is a halls level color1 = 0x801500; color2 = 0xa68521; break; } viewDistance = 8; } private static final int ROOM_LEFT = WIDTH / 2 - 2; private static final int ROOM_RIGHT = WIDTH / 2 + 2; private static final int ROOM_TOP = HEIGHT / 2 - 2; private static final int ROOM_BOTTOM = HEIGHT / 2 + 2; @Override public String tilesTex() { switch (THEME) { case 0: // sewers return Assets.TILES_SEWERS; case 1: // prison return Assets.TILES_PRISON; case 2: // caves return Assets.TILES_CAVES; case 3: // city return Assets.TILES_CITY; case 4: // frozen return Assets.TILES_FROZEN; default: // halls return Assets.TILES_HALLS; } } @Override public String waterTex() { switch (THEME) { case 0: // sewers return Assets.WATER_SEWERS; case 1: // prison return Assets.WATER_PRISON; case 2: // caves return Assets.WATER_CAVES; case 3: // city return Assets.WATER_CITY; case 4: // frozen return Assets.WATER_FROZEN; default: // halls return Assets.WATER_HALLS; } } @Override protected boolean build() { int topMost = Integer.MAX_VALUE; for (int i=0; i < 8; i++) { int left, right, top, bottom; if (Random.Int( 2 ) == 0) { left = Random.Int( 6, ROOM_LEFT - 3 ); right = ROOM_RIGHT + 3; } else { left = ROOM_LEFT - 3; right = Random.Int( ROOM_RIGHT + 3, WIDTH - 6 ); } if (Random.Int( 2 ) == 0) { top = Random.Int( 6, ROOM_TOP - 3 ); bottom = ROOM_BOTTOM + 3; } else { top = ROOM_LEFT - 3; bottom = Random.Int( ROOM_TOP + 3, HEIGHT - 6 ); } Painter.fill(this, left, top, right - left + 1, bottom - top + 1, Terrain.EMPTY); if (top < topMost) { topMost = top; exit = Random.Int( left, right ) + (top - 1) * WIDTH; } } for (int i = 0; i < 3; i++) { int left = Random.IntRange(10, WIDTH-10); int top = Random.IntRange(topMost + 5, HEIGHT-12); Painter.fill(this, left, top, 3, 3, Terrain.WALL); } for (int i = 0; i < 6; i++) { int left = Random.IntRange(10, WIDTH-10); int top = Random.IntRange(topMost + 4, HEIGHT-6); Painter.fill(this, left, top, 2, 2, Terrain.WALL); } map[exit] = Terrain.EXIT; boolean[] patch; switch (Random.Int(4)) { case 0: feeling = Feeling.BURNT; for (int i = 0; i < LENGTH; i++) { if (map[i] == Terrain.EMPTY && Random.Int(6) == 0) { map[i] = Terrain.EMBERS; } } patch = Patch.generate(0.45f, 6); for (int i = 0; i < LENGTH; i++) { if (map[i] == Terrain.EMPTY && patch[i]) { map[i] = Terrain.WATER; } } break; default: feeling = Feeling.GRASS; for (int i = 0; i < LENGTH; i++) { if (map[i] == Terrain.EMPTY && Random.Int(6) == 0) { map[i] = Terrain.HIGH_GRASS; } } patch = Patch.generate(0.45f, 6); for (int i = 0; i < LENGTH; i++) { if (map[i] == Terrain.EMPTY && patch[i]) { map[i] = Terrain.WATER; } } } entrance = Random.Int( ROOM_LEFT + 3, ROOM_RIGHT - 3 ) + Random.Int( ROOM_TOP + 3, ROOM_BOTTOM - 3 ) * WIDTH; Painter.fill(this, (ROOM_LEFT - 2), (ROOM_TOP - 2), 5, 5, Terrain.EMPTY); map[entrance] = Terrain.ENTRANCE; return true; } @Override protected void decorate() { for (int i=WIDTH + 1; i < LENGTH - WIDTH; i++) { if (map[i] == Terrain.EMPTY) { int n = 0; if (map[i+1] == Terrain.WALL) { n++; } if (map[i-1] == Terrain.WALL) { n++; } if (map[i+WIDTH] == Terrain.WALL) { n++; } if (map[i-WIDTH] == Terrain.WALL) { n++; } if (Random.Int( 8 ) <= n) { map[i] = Terrain.EMPTY_DECO; } } } for (int i=0; i < LENGTH; i++) { if (map[i] == Terrain.WALL && Random.Int( 8 ) == 0) { map[i] = Terrain.WALL_DECO; } } int sign; Painter.fill(this, (ROOM_LEFT - 2), (ROOM_TOP - 2), 5, 5, Terrain.EMPTY); do { sign = Random.Int( ROOM_LEFT, ROOM_RIGHT ) + Random.Int( ROOM_TOP, ROOM_BOTTOM ) * WIDTH; } while (sign == entrance); map[sign] = Terrain.SIGN; map[entrance] = Terrain.ENTRANCE; } @Override protected void createItems() { int nItems = 5; int bonus = 0; for (Buff buff : Dungeon.hero.buffs(RingOfWealth.Wealth.class)) { bonus += ((RingOfWealth.Wealth) buff).level; } //just incase someone gets a ridiculous ring, cap this at 80% bonus = Math.min(bonus, 9); while (Random.Float() < (0.35f + bonus*0.05f)) { nItems++; } if (Dungeon.difficultyLevel == Dungeon.DIFF_NTMARE) { nItems = nItems / 2; } else if (Dungeon.difficultyLevel <= Dungeon.DIFF_EASY) { nItems += 2; } for (int i=0; i < nItems; i++) { Heap.Type type = null; switch (Random.Int( 20 )) { case 0: type = Heap.Type.SKELETON; break; case 1: case 2: case 3: case 4: if (feeling == Feeling.BURNT) { // burnt levels drop skeletons instead of chests type = Heap.Type.SKELETON; } else { type = Heap.Type.CHEST; } break; case 5: type = Heap.Type.MIMIC; break; default: type = Heap.Type.HEAP; } drop( Generator.random(), randomDestination() ).type = type; } } protected void createMobs() { int mobsToSpawn = nMobs(); while (mobsToSpawn > 0) { Mob mob = Bestiary.mob(Dungeon.depth); if (mob != null) { mob.pos = randomDestination(); mobsToSpawn--; mobs.add(mob); } } if (Dungeon.depth == 11) { Necromancer necromancer = new Necromancer(); necromancer.scaleMob(); do { necromancer.pos = randomRespawnCell(); } while (necromancer.pos == -1); mobs.add(necromancer); } } @Override public void addVisuals( Scene scene ) { switch (THEME) { case 0: // sewers SewerLevel.addVisuals( this, scene ); break; case 1: // prison PrisonLevel.addVisuals( this, scene ); break; case 2: // caves CavesLevel.addVisuals( this, scene ); break; case 3: // city CityLevel.addVisuals( this, scene ); break; case 4: // frozen FrozenLevel.addVisuals(this, scene); break; default: // halls HallsLevel.addVisuals( this, scene ); break; } } @Override public int nMobs() { switch (Dungeon.difficultyLevel) { case Dungeon.DIFF_TUTOR: case Dungeon.DIFF_EASY: return 4 + Dungeon.depth % 6 + Random.Int(4); case Dungeon.DIFF_HARD: return 6 + Dungeon.depth % 6 + Random.Int(5); case Dungeon.DIFF_NTMARE: return 7 + Dungeon.depth % 6 + Random.Int(6); default: return 5 + Dungeon.depth % 6 + Random.Int(4); } } }