/* Minetest Copyright (C) 2010-2013 celeron55, Perttu Ahola This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "dungeongen.h" #include "mapgen.h" #include "voxel.h" #include "noise.h" #include "mapblock.h" #include "mapnode.h" #include "map.h" #include "nodedef.h" #include "profiler.h" #include "settings.h" //#define DGEN_USE_TORCHES NoiseParams nparams_dungeon_rarity(0.0, 1.0, v3f(500.0, 500.0, 500.0), 0, 2, 0.8, 2.0); NoiseParams nparams_dungeon_wetness(0.0, 1.0, v3f(40.0, 40.0, 40.0), 32474, 4, 1.1, 2.0); NoiseParams nparams_dungeon_density(0.0, 1.0, v3f(2.5, 2.5, 2.5), 0, 2, 1.4, 2.0); /////////////////////////////////////////////////////////////////////////////// DungeonGen::DungeonGen(Mapgen *mapgen, DungeonParams *dparams) { this->mg = mapgen; this->vm = mapgen->vm; #ifdef DGEN_USE_TORCHES c_torch = ndef->getId("default:torch"); #endif if (dparams) { memcpy(&dp, dparams, sizeof(dp)); } else { dp.c_water = mg->ndef->getId("mapgen_water_source"); dp.c_cobble = mg->ndef->getId("mapgen_cobble"); dp.c_moss = mg->ndef->getId("mapgen_mossycobble"); dp.c_stair = mg->ndef->getId("mapgen_stair_cobble"); dp.diagonal_dirs = false; dp.mossratio = 3.0; dp.holesize = v3s16(1, 2, 1); dp.roomsize = v3s16(0, 0, 0); dp.notifytype = GENNOTIFY_DUNGEON; dp.np_rarity = nparams_dungeon_rarity; dp.np_wetness = nparams_dungeon_wetness; dp.np_density = nparams_dungeon_density; } // For mapgens using river water dp.c_river_water = mg->ndef->getId("mapgen_river_water_source"); if (dp.c_river_water == CONTENT_IGNORE) dp.c_river_water = mg->ndef->getId("mapgen_water_source"); } void DungeonGen::generate(u32 bseed, v3s16 nmin, v3s16 nmax) { //TimeTaker t("gen dungeons"); if (NoisePerlin3D(&dp.np_rarity, nmin.X, nmin.Y, nmin.Z, mg->seed) < 0.2) return; this->blockseed = bseed; random.seed(bseed + 2); // Dungeon generator doesn't modify places which have this set vm->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE | VMANIP_FLAG_DUNGEON_PRESERVE); // Set all air and water to be untouchable // to make dungeons open to caves and open air for (s16 z = nmin.Z; z <= nmax.Z; z++) { for (s16 y = nmin.Y; y <= nmax.Y; y++) { u32 i = vm->m_area.index(nmin.X, y, z); for (s16 x = nmin.X; x <= nmax.X; x++) { content_t c = vm->m_data[i].getContent(); if (c == CONTENT_AIR || c == dp.c_water || c == dp.c_river_water) vm->m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE; i++; } } } // Add it makeDungeon(v3s16(1, 1, 1) * MAP_BLOCKSIZE); // Convert some cobble to mossy cobble if (dp.mossratio != 0.0) { for (s16 z = nmin.Z; z <= nmax.Z; z++) for (s16 y = nmin.Y; y <= nmax.Y; y++) { u32 i = vm->m_area.index(nmin.X, y, z); for (s16 x = nmin.X; x <= nmax.X; x++) { if (vm->m_data[i].getContent() == dp.c_cobble) { float wetness = NoisePerlin3D(&dp.np_wetness, x, y, z, mg->seed); float density = NoisePerlin3D(&dp.np_density, x, y, z, blockseed); if (density < wetness / dp.mossratio) vm->m_data[i].setContent(dp.c_moss); } i++; } } } //printf("== gen dungeons: %dms\n", t.stop()); } void DungeonGen::makeDungeon(v3s16 start_padding) { v3s16 areasize = vm->m_area.getExtent(); v3s16 roomsize; v3s16 roomplace; /* Find place for first room */ bool fits = false; for (u32 i = 0; i < 100 && !fits; i++) { bool is_large_room = ((random.next() & 3) == 1); roomsize = is_large_room ? v3s16(random.range(8, 16), random.range(8, 16), random.range(8, 16)) : v3s16(random.range(4, 8), random.range(4, 6), random.range(4, 8)); roomsize += dp.roomsize; // start_padding is used to disallow starting the generation of // a dungeon in a neighboring generation chunk roomplace = vm->m_area.MinEdge + start_padding + v3s16( random.range(0, areasize.X - roomsize.X - start_padding.X), random.range(0, areasize.Y - roomsize.Y - start_padding.Y), random.range(0, areasize.Z - roomsize.Z - start_padding.Z)); /* Check that we're not putting the room to an unknown place, otherwise it might end up floating in the air */ fits = true; for (s16 z = 0; z < roomsize.Z; z++) for (s16 y = 0; y < roomsize.Y; y++) for (s16 x = 0; x < roomsize.X; x++) { v3s16 p = roomplace + v3s16(x, y, z); u32 vi = vm->m_area.index(p); if ((vm->m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE) || vm->m_data[vi].getContent() == CONTENT_IGNORE) { fits = false; break; } } } // No place found if (fits == false) return; /* Stores the center position of the last room made, so that a new corridor can be started from the last room instead of the new room, if chosen so. */ v3s16 last_room_center = roomplace + v3s16(roomsize.X / 2, 1, roomsize.Z / 2); u32 room_count = random.range(2, 16); for (u32 i = 0; i < room_count; i++) { // Make a room to the determined place makeRoom(roomsize, roomplace); v3s16 room_center = roomplace + v3s16(roomsize.X / 2, 1, roomsize.Z / 2); mg->gennotify.addEvent(dp.notifytype, room_center); #ifdef DGEN_USE_TORCHES // Place torch at room center (for testing) vm->m_data[vm->m_area.index(room_center)] = MapNode(c_torch); #endif // Quit if last room if (i == room_count - 1) break; // Determine walker start position bool start_in_last_room = (random.range(0, 2) != 0); v3s16 walker_start_place; if (start_in_last_room) { walker_start_place = last_room_center; } else { walker_start_place = room_center; // Store center of current room as the last one last_room_center = room_center; } // Create walker and find a place for a door v3s16 doorplace; v3s16 doordir; m_pos = walker_start_place; if (!findPlaceForDoor(doorplace, doordir)) return; if (random.range(0, 1) == 0) // Make the door makeDoor(doorplace, doordir); else // Don't actually make a door doorplace -= doordir; // Make a random corridor starting from the door v3s16 corridor_end; v3s16 corridor_end_dir; makeCorridor(doorplace, doordir, corridor_end, corridor_end_dir); // Find a place for a random sized room roomsize = v3s16(random.range(4, 8), random.range(4, 6), random.range(4, 8)); roomsize += dp.roomsize; m_pos = corridor_end; m_dir = corridor_end_dir; if (!findPlaceForRoomDoor(roomsize, doorplace, doordir, roomplace)) return; if (random.range(0, 1) == 0) // Make the door makeDoor(doorplace, doordir)/* base64.cpp and base64.h Copyright (C) 2004-2008 René Nyffenegger This source code is provided 'as-is', without any express or implied warranty. In no event will the author be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this source code must not be misrepresented; you must not claim that you wrote the original source code. If you use this source code in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original source code. 3. This notice may not be removed or altered from any source distribution. René Nyffenegger rene.nyffenegger@adp-gmbh.ch */ #include "base64.h" #include <iostream> static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/"; static inline bool is_base64(unsigned char c) { return (isalnum(c) || (c == '+') || (c == '/')); } bool base64_is_valid(std::string const& s) { for(size_t i=0; i<s.size(); i++) if(!is_base64(s[i])) return false; return true; } std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) { std::string ret; int i = 0; int j = 0; unsigned char char_array_3[3]; unsigned char char_array_4[4]; while (in_len--) { char_array_3[i++] = *(bytes_to_encode++); if (i == 3) { char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); char_array_4[3] = char_array_3[2] & 0x3f; for(i = 0; (i <4) ; i++) ret += base64_chars[char_array_4[i]]; i = 0; } } if (i) { for(j = i; j < 3; j++) char_array_3[j] = '\0'; char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); char_array_4[3] = char_array_3[2] & 0x3f; for (