From c893958bb1a7b6ef08b15914e081ba3df5153693 Mon Sep 17 00:00:00 2001 From: MetaDucky Date: Sun, 26 May 2013 12:06:35 +0200 Subject: Fix some nullptr exceptions when handling invalid node inventories --- src/script/lua_api/l_inventory.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'src/script/lua_api') diff --git a/src/script/lua_api/l_inventory.cpp b/src/script/lua_api/l_inventory.cpp index 1404c3c8a..f57a4e8cd 100644 --- a/src/script/lua_api/l_inventory.cpp +++ b/src/script/lua_api/l_inventory.cpp @@ -121,6 +121,9 @@ int InvRef::l_set_size(lua_State *L) const char *listname = luaL_checkstring(L, 2); int newsize = luaL_checknumber(L, 3); Inventory *inv = getinv(L, ref); + if(inv == NULL){ + return 0; + } if(newsize == 0){ inv->deleteList(listname); reportInventoryChange(L, ref); @@ -144,6 +147,9 @@ int InvRef::l_set_width(lua_State *L) const char *listname = luaL_checkstring(L, 2); int newwidth = luaL_checknumber(L, 3); Inventory *inv = getinv(L, ref); + if(inv == NULL){ + return 0; + } InventoryList *list = inv->getList(listname); if(list){ list->setWidth(newwidth); @@ -195,7 +201,11 @@ int InvRef::l_get_list(lua_State *L) InvRef *ref = checkobject(L, 1); const char *listname = luaL_checkstring(L, 2); Inventory *inv = getinv(L, ref); - push_inventory_list(inv, listname, L); + if(inv){ + push_inventory_list(inv, listname, L); + } else { + lua_pushnil(L); + } return 1; } @@ -206,6 +216,9 @@ int InvRef::l_set_list(lua_State *L) InvRef *ref = checkobject(L, 1); const char *listname = luaL_checkstring(L, 2); Inventory *inv = getinv(L, ref); + if(inv == NULL){ + return 0; + } InventoryList *list = inv->getList(listname); if(list) read_inventory_list(inv, listname, L, 3, -- cgit v1.2.3 From c25102a4f728124b31400ced51cab27eb2f9a5d1 Mon Sep 17 00:00:00 2001 From: sapier Date: Sun, 26 May 2013 18:23:22 +0200 Subject: Fix missing find_path and line_of_sight --- src/script/lua_api/l_env.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'src/script/lua_api') diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index 58cf337ed..a287281a9 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -550,7 +550,7 @@ int ModApiEnvMod::l_line_of_sight(lua_State *L) { GET_ENV_PTR; // read position 1 from lua - v3f pos1 = checkFloatPos(L, 2); + v3f pos1 = checkFloatPos(L, 1); // read position 2 from lua v3f pos2 = checkFloatPos(L, 2); //read step size from lua @@ -566,14 +566,14 @@ int ModApiEnvMod::l_find_path(lua_State *L) { GET_ENV_PTR; - v3s16 pos1 = read_v3s16(L, 2); - v3s16 pos2 = read_v3s16(L, 3); - unsigned int searchdistance = luaL_checkint(L, 4); - unsigned int max_jump = luaL_checkint(L, 5); - unsigned int max_drop = luaL_checkint(L, 6); + v3s16 pos1 = read_v3s16(L, 1); + v3s16 pos2 = read_v3s16(L, 2); + unsigned int searchdistance = luaL_checkint(L, 3); + unsigned int max_jump = luaL_checkint(L, 4); + unsigned int max_drop = luaL_checkint(L, 5); algorithm algo = A_PLAIN_NP; - if(! lua_isnil(L, 7)) { - std::string algorithm = luaL_checkstring(L,7); + if(! lua_isnil(L, 6)) { + std::string algorithm = luaL_checkstring(L,6); if (algorithm == "A*") algo = A_PLAIN; @@ -680,6 +680,8 @@ bool ModApiEnvMod::Initialize(lua_State *L,int top) retval &= API_FCT(get_perlin_map); retval &= API_FCT(clear_objects); retval &= API_FCT(spawn_tree); + retval &= API_FCT(find_path); + retval &= API_FCT(line_of_sight); return retval; } -- cgit v1.2.3 From 601ab852261e8db3edfbd75fe9664296513e6f97 Mon Sep 17 00:00:00 2001 From: sweetbomber Date: Mon, 3 Jun 2013 15:59:13 +0100 Subject: Corrected segfault when registering new biomes. --- src/script/lua_api/luaapi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/script/lua_api') diff --git a/src/script/lua_api/luaapi.cpp b/src/script/lua_api/luaapi.cpp index b75304b3a..6d7e32730 100644 --- a/src/script/lua_api/luaapi.cpp +++ b/src/script/lua_api/luaapi.cpp @@ -178,9 +178,9 @@ int ModApiBasic::l_register_biome(lua_State *L) b->flags = 0; //reserved b->c_top = CONTENT_IGNORE; b->c_filler = CONTENT_IGNORE; + verbosestream << "register_biome: " << b->name << std::endl; bmgr->addBiome(b); - verbosestream << "register_biome: " << b->name << std::endl; return 0; } -- cgit v1.2.3 From 44053101840594e133886986d28e557bdfb57e8b Mon Sep 17 00:00:00 2001 From: Kahrl Date: Sun, 16 Jun 2013 14:07:12 +0200 Subject: Lazy sunday typo fixing. s/unban_player_of_ip/unban_player_or_ip/g --- src/script/lua_api/luaapi.cpp | 4 ++-- src/script/lua_api/luaapi.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/script/lua_api') diff --git a/src/script/lua_api/luaapi.cpp b/src/script/lua_api/luaapi.cpp index 6d7e32730..180a44b26 100644 --- a/src/script/lua_api/luaapi.cpp +++ b/src/script/lua_api/luaapi.cpp @@ -72,7 +72,7 @@ bool ModApiBasic::Initialize(lua_State* L,int top) { retval &= API_FCT(get_ban_list); retval &= API_FCT(get_ban_description); retval &= API_FCT(ban_player); - retval &= API_FCT(unban_player_of_ip); + retval &= API_FCT(unban_player_or_ip); retval &= API_FCT(get_password_hash); retval &= API_FCT(notify_authentication_modified); @@ -353,7 +353,7 @@ int ModApiBasic::l_ban_player(lua_State *L) } // unban_player_or_ip() -int ModApiBasic::l_unban_player_of_ip(lua_State *L) +int ModApiBasic::l_unban_player_or_ip(lua_State *L) { NO_MAP_LOCK_REQUIRED; const char * ip_or_name = luaL_checkstring(L, 1); diff --git a/src/script/lua_api/luaapi.h b/src/script/lua_api/luaapi.h index 592046965..9623502c2 100644 --- a/src/script/lua_api/luaapi.h +++ b/src/script/lua_api/luaapi.h @@ -85,7 +85,7 @@ private: static int l_ban_player(lua_State *L); // unban_player_or_ip() - static int l_unban_player_of_ip(lua_State *L); + static int l_unban_player_or_ip(lua_State *L); // show_formspec(playername,formname,formspec) static int l_show_formspec(lua_State *L); -- cgit v1.2.3 From 0a8519a26fc7c10b4e7415746e9045caa3ae978f Mon Sep 17 00:00:00 2001 From: kwolekr Date: Sat, 15 Jun 2013 22:23:06 -0400 Subject: Add initial Decoration support, many misc. improvements & modifications --- doc/lua_api.txt | 49 +++++- src/biome.cpp | 10 ++ src/biome.h | 1 + src/defaultsettings.cpp | 2 +- src/emerge.cpp | 4 + src/emerge.h | 1 + src/mapgen.cpp | 378 ++++++++++++++++++++++++++++++++++++++---- src/mapgen.h | 91 ++++++++++ src/mapgen_v6.cpp | 23 +-- src/mapgen_v6.h | 1 - src/mapgen_v7.cpp | 33 ++-- src/mapgen_v7.h | 2 - src/script/lua_api/luaapi.cpp | 142 ++++++++++++++-- src/script/lua_api/luaapi.h | 9 +- 14 files changed, 659 insertions(+), 87 deletions(-) (limited to 'src/script/lua_api') diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 93e2d5c9f..b6981582e 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -410,6 +410,18 @@ Currently supported flags: absheight Also produce this same ore between the height range of -height_max and -height_min. Useful for having ore in sky realms without having to duplicate ore entries. +Decoration types +------------------- +The varying types of decorations that can be placed. +The default value is simple, and is currently the only type supported. + +- simple + Creates a 1xHx1 column of a specified node (or a random node from a list, if a decoration + list is specified). Can specify a certain node it must spawn next to, such as water or lava, + for example. Can also generate a decoration of random height between a specified lower and + upper bound. This type of decoration is intended for placement of grass, flowers, cacti, + papyrus, and so on. + HUD element types ------------------- The position field is used for all element types. @@ -946,6 +958,7 @@ minetest.register_craftitem(name, item definition) minetest.register_alias(name, convert_to) minetest.register_craft(recipe) minetest.register_ore(ore definition) +minetest.register_decoration(decoration definition) Global callback registration functions: (Call these only at load time) minetest.register_globalstep(func(dtime)) @@ -1835,7 +1848,7 @@ Recipe for register_craft (furnace fuel) Ore definition (register_ore) { - ore_type = "scatter" -- See "Ore types" + ore_type = "scatter", -- See "Ore types" ore = "default:stone_with_coal", wherein = "default:stone", clust_scarcity = 8*8*8, @@ -1857,6 +1870,40 @@ Ore definition (register_ore) ^ Needed for sheet ore_type. Omit from scatter ore_type for a uniform ore distribution } +Decoration definition (register_decoration) +{ + deco_type = "simple", -- See "Decoration types" + place_on = "default:dirt_with_grass", + ^ Node that decoration can be placed on + divlen = 8, + ^ Number of divisions made in the chunk being generated + fill_ratio = 0.02, + ^ Ratio of the area to be uniformly filled by the decoration. + ^ Used only if noise_params is not specified. + noise_params = {offset=0, scale=.45, spread={x=100, y=100, z=100}, seed=354, octaves=3, persist=0.7}, + ^ NoiseParams structure describing the perlin noise used for decoration distribution. + ^ The result of this is multiplied by the 2d area of the division being decorated. + biomes = {"Oceanside", "Hills", "Plains"}, + ^ List of biomes in which this decoration occurs. Occurs in all biomes if this is omitted, + ^ and ignored if the Mapgen being used does not support biomes. + + ----- Simple-type parameters + decoration = "default:grass", + ^ The node name used as the decoration. + ^ If instead a list of strings, a randomly selected node from the list is placed as the decoration. + height = 1, + ^ Number of nodes high the decoration is made. + ^ If height_max is not 0, this is the lower bound of the randomly selected height. + height_max = 0, + ^ Number of nodes the decoration can be at maximum. + ^ If absent, the parameter 'height' is used as a constant. + spawn_by = "default:water", + ^ Node that the decoration only spawns next to, in a 1-node square radius. + num_spawn_by = 1, + ^ Number of spawn_by nodes that must be surrounding the decoration position to occur. + ^ If absent or -1, decorations occur next to any nodes. +} + Chatcommand definition (register_chatcommand) { params = " ", -- short parameter description diff --git a/src/biome.cpp b/src/biome.cpp index b50c562a0..bc84d4bc1 100644 --- a/src/biome.cpp +++ b/src/biome.cpp @@ -168,3 +168,13 @@ Biome *BiomeDefManager::getBiome(float heat, float humidity, s16 y) { return biome_closest ? biome_closest : biomes[0]; } + + +u8 BiomeDefManager::getBiomeIdByName(const char *name) { + for (size_t i = 0; i != biomes.size(); i++) { + if (!strcasecmp(name, biomes[i]->name.c_str())) + return i; + } + + return 0; +} diff --git a/src/biome.h b/src/biome.h index 17703db5a..535dc4989 100644 --- a/src/biome.h +++ b/src/biome.h @@ -84,6 +84,7 @@ public: void addBiome(Biome *b); void resolveNodeNames(INodeDefManager *ndef); + u8 getBiomeIdByName(const char *name); }; #endif diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index d2bed7ed8..71c283241 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -239,7 +239,7 @@ void set_default_settings(Settings *settings) settings->setDefault("mgv7_np_terrain_mod", "0, 1, (350, 350, 350), 85039, 5, 0.6"); settings->setDefault("mgv7_np_terrain_persist", "0, 1, (500, 500, 500), 539, 3, 0.6"); settings->setDefault("mgv7_np_height_select", "0.5, 0.5, (250, 250, 250), 4213, 5, 0.69"); - settings->setDefault("mgv7_np_ridge", "0.5, 1, (100, 100, 100), 6467, 4, 0.75"); + settings->setDefault("mgv7_np_ridge", "0, 1, (100, 100, 100), 6467, 4, 0.75"); settings->setDefault("mgindev_np_terrain_base", "-4, 20, (250, 250, 250), 82341, 5, 0.6, 10, 10"); settings->setDefault("mgindev_np_terrain_higher", "20, 16, (500, 500, 500), 85039, 5, 0.6, 10, 10"); diff --git a/src/emerge.cpp b/src/emerge.cpp index fd6c0e91f..2c94d46c1 100644 --- a/src/emerge.cpp +++ b/src/emerge.cpp @@ -101,6 +101,10 @@ EmergeManager::~EmergeManager() { for (unsigned int i = 0; i < ores.size(); i++) delete ores[i]; ores.clear(); + + for (unsigned int i = 0; i < decorations.size(); i++) + delete decorations[i]; + decorations.clear(); for (std::map::iterator iter = mglist.begin(); iter != mglist.end(); iter ++) { diff --git a/src/emerge.h b/src/emerge.h index b42e82d38..084956932 100644 --- a/src/emerge.h +++ b/src/emerge.h @@ -87,6 +87,7 @@ public: //Mapgen-related structures BiomeDefManager *biomedef; std::vector ores; + std::vector decorations; EmergeManager(IGameDef *gamedef); ~EmergeManager(); diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 835c14be1..49ac827e1 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -87,7 +87,7 @@ void Ore::resolveNodeNames(INodeDefManager *ndef) { wherein = CONTENT_AIR; } } - + if (wherein == CONTENT_IGNORE) { wherein = ndef->getId(wherein_name); if (wherein == CONTENT_IGNORE) { @@ -110,9 +110,8 @@ void Ore::placeOre(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) { return; resolveNodeNames(mg->ndef); - + int ymin, ymax; - if (in_range & ORE_RANGE_MIRROR) { ymin = MYMAX(nmin.Y, -height_max); ymax = MYMIN(nmax.Y, -height_min); @@ -122,7 +121,7 @@ void Ore::placeOre(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) { } if (clust_size >= ymax - ymin + 1) return; - + nmin.Y = ymin; nmax.Y = ymax; generate(mg->vm, mg->seed, blockseed, nmin, nmax); @@ -130,7 +129,7 @@ void Ore::placeOre(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) { void OreScatter::generate(ManualMapVoxelManipulator *vm, int seed, - u32 blockseed, v3s16 nmin, v3s16 nmax) { + u32 blockseed, v3s16 nmin, v3s16 nmax) { PseudoRandom pr(blockseed); MapNode n_ore(ore, 0, ore_param2); @@ -145,16 +144,16 @@ void OreScatter::generate(ManualMapVoxelManipulator *vm, int seed, int x0 = pr.range(nmin.X, nmax.X - csize + 1); int y0 = pr.range(nmin.Y, nmax.Y - csize + 1); int z0 = pr.range(nmin.Z, nmax.Z - csize + 1); - + if (np && (NoisePerlin3D(np, x0, y0, z0, seed) < nthresh)) continue; - + for (int z1 = 0; z1 != csize; z1++) for (int y1 = 0; y1 != csize; y1++) for (int x1 = 0; x1 != csize; x1++) { if (pr.range(1, orechance) != 1) continue; - + u32 i = vm->m_area.index(x0 + x1, y0 + y1, z0 + z1); if (vm->m_data[i].getContent() == wherein) vm->m_data[i] = n_ore; @@ -167,10 +166,10 @@ void OreSheet::generate(ManualMapVoxelManipulator *vm, int seed, u32 blockseed, v3s16 nmin, v3s16 nmax) { PseudoRandom pr(blockseed + 4234); MapNode n_ore(ore, 0, ore_param2); - + int max_height = clust_size; int y_start = pr.range(nmin.Y, nmax.Y - max_height); - + if (!noise) { int sx = nmax.X - nmin.X + 1; int sz = nmax.Z - nmin.Z + 1; @@ -178,14 +177,14 @@ void OreSheet::generate(ManualMapVoxelManipulator *vm, int seed, } noise->seed = seed + y_start; noise->perlinMap2D(nmin.X, nmin.Z); - + int index = 0; for (int z = nmin.Z; z <= nmax.Z; z++) for (int x = nmin.X; x <= nmax.X; x++) { float noiseval = noise->result[index++]; if (noiseval < nthresh) continue; - + int height = max_height * (1. / pr.range(1, 3)); int y0 = y_start + np->scale * noiseval; //pr.range(1, 3) - 1; int y1 = y0 + height; @@ -193,7 +192,7 @@ void OreSheet::generate(ManualMapVoxelManipulator *vm, int seed, u32 i = vm->m_area.index(x, y, z); if (!vm->m_area.contains(i)) continue; - + if (vm->m_data[i].getContent() == wherein) vm->m_data[i] = n_ore; } @@ -201,6 +200,316 @@ void OreSheet::generate(ManualMapVoxelManipulator *vm, int seed, } +Decoration *createDecoration(DecorationType type) { + switch (type) { + case DECO_SIMPLE: + return new DecoSimple; + //case DECO_SCHEMATIC: + // return new DecoSchematic; + //case DECO_LSYSTEM: + // return new DecoLSystem; + default: + return NULL; + } +} + + +Decoration::~Decoration() { + delete np; +} + + +void Decoration::resolveNodeNames(INodeDefManager *ndef) { + if (c_place_on == CONTENT_IGNORE) + c_place_on = ndef->getId(place_on_name); +} + + +void Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) { + resolveNodeNames(mg->ndef); + + PseudoRandom ps(blockseed + 53); + int carea_size = nmax.X - nmin.X + 1; + + // Divide area into parts + s16 sidelen = carea_size / divlen; + float area = sidelen * sidelen; + + for (s16 z0 = 0; z0 < divlen; z0++) + for (s16 x0 = 0; x0 < divlen; x0++) { + v2s16 p2d_center( // Center position of part of division + nmin.X + sidelen / 2 + sidelen * x0, + nmin.Z + sidelen / 2 + sidelen * z0 + ); + v2s16 p2d_min( // Minimum edge of part of division + nmin.X + sidelen * x0, + nmin.Z + sidelen * z0 + ); + v2s16 p2d_max( // Maximum edge of part of division + nmin.X + sidelen + sidelen * x0 - 1, + nmin.Z + sidelen + sidelen * z0 - 1 + ); + + // Amount of decorations + float nval = np ? + NoisePerlin2D(np, p2d_center.X, p2d_center.Y, mapseed) : + fill_ratio; + u32 deco_count = area * MYMAX(nval, 0.f); + + for (u32 i = 0; i < deco_count; i++) { + s16 x = ps.range(p2d_min.X, p2d_max.X); + s16 z = ps.range(p2d_min.Y, p2d_max.Y); + + int mapindex = carea_size * (z - nmin.Z) + (x - nmin.X); + + s16 y = mg->heightmap ? + mg->heightmap[mapindex] : + mg->findGroundLevel(v2s16(x, z), nmin.Y, nmax.Y); + + if (y < nmin.Y || y > nmax.Y) + continue; + + int height = getHeight(); + int max_y = nmax.Y + MAP_BLOCKSIZE; + if (y + 1 + height > max_y) { + continue; +#if 0 + printf("Decoration at (%d %d %d) cut off\n", x, y, z); + //add to queue + JMutexAutoLock cutofflock(cutoff_mutex); + cutoffs.push_back(CutoffData(x, y, z, height)); +#endif + } + + if (mg->biomemap) { + std::set::iterator iter; + + if (biomes.size()) { + iter = biomes.find(mg->biomemap[mapindex]); + if (iter == biomes.end()) + continue; + } + } + + generate(mg, &ps, max_y, 0, v3s16(x, y, z)); + } + } +} + + +#if 0 +void Decoration::placeCutoffs(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) { + PseudoRandom pr(blockseed + 53); + std::vector handled_cutoffs; + + // Copy over the cutoffs we're interested in so we don't needlessly hold a lock + { + JMutexAutoLock cutofflock(cutoff_mutex); + for (std::list::iterator i = cutoffs.begin(); + i != cutoffs.end(); ++i) { + CutoffData cutoff = *i; + v3s16 p = cutoff.p; + s16 height = cutoff.height; + if (p.X < nmin.X || p.X > nmax.X || + p.Z < nmin.Z || p.Z > nmax.Z) + continue; + if (p.Y + height < nmin.Y || p.Y > nmax.Y) + continue; + + handled_cutoffs.push_back(cutoff); + } + } + + // Generate the cutoffs + for (size_t i = 0; i != handled_cutoffs.size(); i++) { + v3s16 p = handled_cutoffs[i].p; + s16 height = handled_cutoffs[i].height; + + if (p.Y + height > nmax.Y) { + //printf("Decoration at (%d %d %d) cut off again!\n", p.X, p.Y, p.Z); + cuttoffs.push_back(v3s16(p.X, p.Y, p.Z)); + } + + generate(mg, &pr, nmax.Y, nmin.Y - p.Y, v3s16(p.X, nmin.Y, p.Z)); + } + + // Remove cutoffs that were handled from the cutoff list + { + JMutexAutoLock cutofflock(cutoff_mutex); + for (std::list::iterator i = cutoffs.begin(); + i != cutoffs.end(); ++i) { + + for (size_t j = 0; j != handled_cutoffs.size(); j++) { + CutoffData coff = *i; + if (coff.p == handled_cutoffs[j].p) + i = cutoffs.erase(i); + } + } + } +} +#endif + + +void DecoSimple::resolveNodeNames(INodeDefManager *ndef) { + Decoration::resolveNodeNames(ndef); + + if (c_deco == CONTENT_IGNORE) { + c_deco = ndef->getId(deco_name); + if (c_deco == CONTENT_IGNORE) { + errorstream << "DecoSimple::resolveNodeNames: decoration node '" + << deco_name << "' not defined"; + c_deco = CONTENT_AIR; + } + } + if (c_spawnby == CONTENT_IGNORE) { + c_spawnby = ndef->getId(spawnby_name); + if (c_spawnby == CONTENT_IGNORE) { + errorstream << "DecoSimple::resolveNodeNames: spawnby node '" + << deco_name << "' not defined"; + nspawnby = -1; + c_spawnby = CONTENT_AIR; + } + } + + if (c_decolist.size()) + return; + + for (size_t i = 0; i != decolist_names.size(); i++) { + content_t c = ndef->getId(decolist_names[i]); + if (c == CONTENT_IGNORE) { + errorstream << "DecoSimple::resolveNodeNames: decolist node '" + << decolist_names[i] << "' not defined"; + c = CONTENT_AIR; + } + c_decolist.push_back(c); + } +} + + +void DecoSimple::generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, s16 start_y, v3s16 p) { + ManualMapVoxelManipulator *vm = mg->vm; + + u32 vi = vm->m_area.index(p); + if (vm->m_data[vi].getContent() != c_place_on && + c_place_on != CONTENT_IGNORE) + return; + + if (nspawnby != -1) { + int nneighs = 0; + v3s16 dirs[8] = { // a Moore neighborhood + v3s16( 0, 0, 1), + v3s16( 0, 0, -1), + v3s16( 1, 0, 0), + v3s16(-1, 0, 0), + v3s16( 1, 0, 1), + v3s16(-1, 0, 1), + v3s16(-1, 0, -1), + v3s16( 1, 0, -1) + }; + + for (int i = 0; i != 8; i++) { + u32 index = vm->m_area.index(p + dirs[i]); + if (vm->m_area.contains(index) && + vm->m_data[index].getContent() == c_spawnby) + nneighs++; + } + + if (nneighs < nspawnby) + return; + } + + size_t ndecos = c_decolist.size(); + content_t c = ndecos ? c_decolist[pr->range(0, ndecos - 1)] : c_deco; + + s16 height = (deco_height_max > 0) ? + pr->range(deco_height, deco_height_max) : deco_height; + + height = MYMIN(height, max_y - p.Y); + + v3s16 em = vm->m_area.getExtent(); + for (int i = start_y; i < height; i++) { + vm->m_area.add_y(em, vi, 1); + vm->m_data[vi] = MapNode(c); + } +} + + +int DecoSimple::getHeight() { + return (deco_height_max > 0) ? deco_height_max : deco_height; +} + + +std::string DecoSimple::getName() { + return deco_name; +} + + +/////////////////////////////////////////////////////////////////////////////// + + +Mapgen::Mapgen() { + seed = 0; + water_level = 0; + generating = false; + id = -1; + vm = NULL; + ndef = NULL; + heightmap = NULL; + biomemap = NULL; +} + + +// Returns Y one under area minimum if not found +s16 Mapgen::findGroundLevelFull(v2s16 p2d) { + v3s16 em = vm->m_area.getExtent(); + s16 y_nodes_max = vm->m_area.MaxEdge.Y; + s16 y_nodes_min = vm->m_area.MinEdge.Y; + u32 i = vm->m_area.index(p2d.X, y_nodes_max, p2d.Y); + s16 y; + + for (y = y_nodes_max; y >= y_nodes_min; y--) { + MapNode &n = vm->m_data[i]; + if (ndef->get(n).walkable) + break; + + vm->m_area.add_y(em, i, -1); + } + return (y >= y_nodes_min) ? y : y_nodes_min - 1; +} + + +s16 Mapgen::findGroundLevel(v2s16 p2d, s16 ymin, s16 ymax) { + v3s16 em = vm->m_area.getExtent(); + u32 i = vm->m_area.index(p2d.X, ymax, p2d.Y); + s16 y; + + for (y = ymax; y >= ymin; y--) { + MapNode &n = vm->m_data[i]; + if (ndef->get(n).walkable) + break; + + vm->m_area.add_y(em, i, -1); + } + return y; +} + + +void Mapgen::updateHeightmap(v3s16 nmin, v3s16 nmax) { + if (!heightmap) + return; + + //TimeTaker t("Mapgen::updateHeightmap", NULL, PRECISION_MICRO); + int index = 0; + for (s16 z = nmin.Z; z <= nmax.Z; z++) { + for (s16 x = nmin.X; x <= nmax.X; x++) { + s16 y = findGroundLevel(v2s16(x, z), nmin.Y, nmax.Y); + heightmap[index++] = y; + } + } + //printf("updateHeightmap: %dus\n", t.stop()); +} + + void Mapgen::updateLiquid(UniqueQueue *trans_liquid, v3s16 nmin, v3s16 nmax) { bool isliquid, wasliquid; v3s16 em = vm->m_area.getExtent(); @@ -208,11 +517,11 @@ void Mapgen::updateLiquid(UniqueQueue *trans_liquid, v3s16 nmin, v3s16 nm for (s16 z = nmin.Z; z <= nmax.Z; z++) { for (s16 x = nmin.X; x <= nmax.X; x++) { wasliquid = true; - + u32 i = vm->m_area.index(x, nmax.Y, z); for (s16 y = nmax.Y; y >= nmin.Y; y--) { isliquid = ndef->get(vm->m_data[i]).isLiquid(); - + // there was a change between liquid and nonliquid, add to queue if (isliquid != wasliquid) trans_liquid->push_back(v3s16(x, y, z)); @@ -242,7 +551,7 @@ void Mapgen::setLighting(v3s16 nmin, v3s16 nmax, u8 light) { void Mapgen::lightSpread(VoxelArea &a, v3s16 p, u8 light) { if (light <= 1 || !a.contains(p)) return; - + u32 vi = vm->m_area.index(p); MapNode &nn = vm->m_data[vi]; @@ -250,9 +559,9 @@ void Mapgen::lightSpread(VoxelArea &a, v3s16 p, u8 light) { // should probably compare masked, but doesn't seem to make a difference if (light <= nn.param1 || !ndef->get(nn).light_propagates) return; - + nn.param1 = light; - + lightSpread(a, p + v3s16(0, 0, 1), light); lightSpread(a, p + v3s16(0, 1, 0), light); lightSpread(a, p + v3s16(1, 0, 0), light); @@ -282,7 +591,7 @@ void Mapgen::calcLighting(v3s16 nmin, v3s16 nmax) { continue; } vm->m_area.add_y(em, i, -1); - + for (int y = a.MaxEdge.Y; y >= a.MinEdge.Y; y--) { MapNode &n = vm->m_data[i]; if (!ndef->get(n).sunlight_propagates) @@ -292,7 +601,7 @@ void Mapgen::calcLighting(v3s16 nmin, v3s16 nmax) { } } } - + // now spread the sunlight and light up any sources for (int z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++) { for (int y = a.MinEdge.Y; y <= a.MaxEdge.Y; y++) { @@ -302,11 +611,11 @@ void Mapgen::calcLighting(v3s16 nmin, v3s16 nmax) { if (n.getContent() == CONTENT_IGNORE || !ndef->get(n).light_propagates) continue; - + u8 light_produced = ndef->get(n).light_source & 0x0F; if (light_produced) n.param1 = light_produced; - + u8 light = n.param1 & 0x0F; if (light) { lightSpread(a, v3s16(x, y, z + 1), light); @@ -319,7 +628,7 @@ void Mapgen::calcLighting(v3s16 nmin, v3s16 nmax) { } } } - + //printf("updateLighting: %dms\n", t.stop()); } @@ -331,24 +640,24 @@ void Mapgen::calcLightingOld(v3s16 nmin, v3s16 nmax) { bool sunlight = !block_is_underground; ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG); - + for (int i = 0; i < 2; i++) { enum LightBank bank = banks[i]; std::set light_sources; std::map unlight_from; voxalgo::clearLightAndCollectSources(*vm, a, bank, ndef, - light_sources, unlight_from); + light_sources, unlight_from); voxalgo::propagateSunlight(*vm, a, sunlight, light_sources, ndef); vm->unspreadLight(bank, unlight_from, light_sources, ndef); vm->spreadLight(bank, light_sources, ndef); } } - - + + //////////////////////// Mapgen V6 parameter read/write - + bool MapgenV6Params::readParams(Settings *settings) { freq_desert = settings->getFloat("mgv6_freq_desert"); freq_beach = settings->getFloat("mgv6_freq_beach"); @@ -367,12 +676,12 @@ bool MapgenV6Params::readParams(Settings *settings) { settings->getNoiseParams("mgv6_np_apple_trees", np_apple_trees); return success; } - - + + void MapgenV6Params::writeParams(Settings *settings) { settings->setFloat("mgv6_freq_desert", freq_desert); settings->setFloat("mgv6_freq_beach", freq_beach); - + settings->setNoiseParams("mgv6_np_terrain_base", np_terrain_base); settings->setNoiseParams("mgv6_np_terrain_higher", np_terrain_higher); settings->setNoiseParams("mgv6_np_steepness", np_steepness); @@ -411,7 +720,6 @@ void MapgenV7Params::writeParams(Settings *settings) { /////////////////////////////////// legacy static functions for farmesh - s16 Mapgen::find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision) { //just need to return something s16 level = 5; @@ -421,9 +729,9 @@ s16 Mapgen::find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision) { bool Mapgen::get_have_beach(u64 seed, v2s16 p2d) { double sandnoise = noise2d_perlin( - 0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250, - seed+59420, 3, 0.50); - + 0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250, + seed+59420, 3, 0.50); + return (sandnoise > 0.15); } diff --git a/src/mapgen.h b/src/mapgen.h index 5d1e3bdf0..e8252cbbf 100644 --- a/src/mapgen.h +++ b/src/mapgen.h @@ -86,9 +86,15 @@ public: int id; ManualMapVoxelManipulator *vm; INodeDefManager *ndef; + s16 *heightmap; + u8 *biomemap; + Mapgen(); virtual ~Mapgen() {} + s16 findGroundLevelFull(v2s16 p2d); + s16 findGroundLevel(v2s16 p2d, s16 ymin, s16 ymax); + void updateHeightmap(v3s16 nmin, v3s16 nmax); void updateLiquid(UniqueQueue *trans_liquid, v3s16 nmin, v3s16 nmax); void setLighting(v3s16 nmin, v3s16 nmax, u8 light); void lightSpread(VoxelArea &a, v3s16 p, u8 light); @@ -166,5 +172,90 @@ class OreSheet : public Ore { Ore *createOre(OreType type); + +enum DecorationType { + DECO_SIMPLE, + DECO_SCHEMATIC, + DECO_LSYSTEM +}; + +#if 0 +struct CutoffData { + VoxelArea a; + Decoration *deco; + //v3s16 p; + //v3s16 size; + //s16 height; + + CutoffData(s16 x, s16 y, s16 z, s16 h) { + p = v3s16(x, y, z); + height = h; + } +}; +#endif + +class Decoration { +public: + int mapseed; + std::string place_on_name; + content_t c_place_on; + s16 divlen; + float fill_ratio; + NoiseParams *np; + + std::set biomes; + //std::list cutoffs; + //JMutex cutoff_mutex; + + virtual ~Decoration(); + + virtual void resolveNodeNames(INodeDefManager *ndef); + void placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax); + void placeCutoffs(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax); + + virtual void generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, + s16 start_y, v3s16 p) = 0; + virtual int getHeight() = 0; + virtual std::string getName() = 0; +}; + +class DecoSimple : public Decoration { +public: + std::string deco_name; + std::string spawnby_name; + content_t c_deco; + content_t c_spawnby; + s16 deco_height; + s16 deco_height_max; + s16 nspawnby; + + std::vector decolist_names; + std::vector c_decolist; + + ~DecoSimple() {} + + void resolveNodeNames(INodeDefManager *ndef); + virtual void generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, + s16 start_y, v3s16 p); + virtual int getHeight(); + virtual std::string getName(); +}; + +/* +class DecoSchematic : public Decoration { +public: + virtual void generate(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax); +}; +*/ + +/* +class DecoLSystem : public Decoration { +public: + virtual void generate(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax); +}; +*/ + +Decoration *createDecoration(DecorationType type); + #endif diff --git a/src/mapgen_v6.cpp b/src/mapgen_v6.cpp index eaca33988..a411f966b 100644 --- a/src/mapgen_v6.cpp +++ b/src/mapgen_v6.cpp @@ -79,7 +79,7 @@ MapgenV6::MapgenV6(int mapgenid, MapgenV6Params *params, EmergeManager *emerge) this->freq_beach = params->freq_beach; this->ystride = csize.X; //////fix this - + np_cave = ¶ms->np_cave; np_humidity = ¶ms->np_humidity; np_trees = ¶ms->np_trees; @@ -108,23 +108,6 @@ MapgenV6::~MapgenV6() { //////////////////////// Some helper functions for the map generator -// Returns Y one under area minimum if not found -s16 MapgenV6::find_ground_level(v2s16 p2d) { - v3s16 em = vm->m_area.getExtent(); - s16 y_nodes_max = vm->m_area.MaxEdge.Y; - s16 y_nodes_min = vm->m_area.MinEdge.Y; - u32 i = vm->m_area.index(p2d.X, y_nodes_max, p2d.Y); - s16 y; - - for (y = y_nodes_max; y >= y_nodes_min; y--) { - MapNode &n = vm->m_data[i]; - if(ndef->get(n).walkable) - break; - - vm->m_area.add_y(em, i, -1); - } - return (y >= y_nodes_min) ? y : y_nodes_min - 1; -} // Returns Y one under area minimum if not found s16 MapgenV6::find_stone_level(v2s16 p2d) { @@ -849,7 +832,7 @@ void MapgenV6::placeTreesAndJungleGrass() { s16 x = grassrandom.range(p2d_min.X, p2d_max.X); s16 z = grassrandom.range(p2d_min.Y, p2d_max.Y); - s16 y = find_ground_level(v2s16(x, z)); ////////////////optimize this! + s16 y = findGroundLevelFull(v2s16(x, z)); ////////////////optimize this! if (y < water_level || y < node_min.Y || y > node_max.Y) continue; @@ -866,7 +849,7 @@ void MapgenV6::placeTreesAndJungleGrass() { for (u32 i = 0; i < tree_count; i++) { s16 x = myrand_range(p2d_min.X, p2d_max.X); s16 z = myrand_range(p2d_min.Y, p2d_max.Y); - s16 y = find_ground_level(v2s16(x, z)); ////////////////////optimize this! + s16 y = findGroundLevelFull(v2s16(x, z)); ////////////////////optimize this! // Don't make a tree under water level // Don't make a tree so high that it doesn't fit if(y < water_level || y > node_max.Y - 6) diff --git a/src/mapgen_v6.h b/src/mapgen_v6.h index 8f456fd3f..f4ffd25f3 100644 --- a/src/mapgen_v6.h +++ b/src/mapgen_v6.h @@ -132,7 +132,6 @@ public: virtual float baseTerrainLevelFromMap(v2s16 p); virtual float baseTerrainLevelFromMap(int index); - s16 find_ground_level(v2s16 p2d); s16 find_stone_level(v2s16 p2d); bool block_is_underground(u64 seed, v3s16 blockpos); s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision); diff --git a/src/mapgen_v7.cpp b/src/mapgen_v7.cpp index 6daa5fc6a..2439c95b3 100644 --- a/src/mapgen_v7.cpp +++ b/src/mapgen_v7.cpp @@ -52,7 +52,7 @@ NoiseParams nparams_v7_def_terrain_persist = NoiseParams nparams_v7_def_height_select = {0.5, 0.5, v3f(250.0, 250.0, 250.0), 4213, 5, 0.69}; NoiseParams nparams_v7_def_ridge = - {0.5, 1.0, v3f(100.0, 100.0, 100.0), 6467, 4, 0.75}; + {0, 1.0, v3f(100.0, 100.0, 100.0), 6467, 4, 0.75}; /* NoiseParams nparams_v6_def_beach = {0.0, 1.0, v3f(250.0, 250.0, 250.0), 59420, 3, 0.50}; @@ -121,15 +121,19 @@ int MapgenV7::getGroundLevelAtPoint(v2s16 p) { Biome *b = bmgr->getBiome(heat, humidity, groundlevel); s16 y = groundlevel; - if (y > water_level) { - int iters = 1024; // don't even bother iterating more than 1024 times.. - while (iters--) { - float ridgenoise = NoisePerlin3D(noise_ridge->np, p.X, y, p.Y, seed); - if (ridgenoise * (float)(y * y) < 15.0) - break; - y--; - } + int iters = 1024; // don't even bother iterating more than 64 times.. + while (iters--) { + if (y <= water_level) + break; + + float ridgenoise = NoisePerlin3D(noise_ridge->np, p.X, y, p.Y, seed); + if (ridgenoise * (float)(y * y) < 15.0) + break; + + y--; } + if (iters == 0) + printf("iters exhausted at %d %d\n", p.X, p.Y); return y + b->top_depth; } @@ -182,15 +186,24 @@ void MapgenV7::makeChunk(BlockMakeData *data) { generateTerrain(); carveRidges(); + + if (flags & MG_CAVES) + generateCaves(stone_surface_max_y); - generateCaves(stone_surface_max_y); addTopNodes(); + + updateHeightmap(node_min, node_max); if (flags & MG_DUNGEONS) { DungeonGen dgen(ndef, data->seed, water_level); dgen.generate(vm, blockseed, full_node_min, full_node_max); } + for (size_t i = 0; i != emerge->decorations.size(); i++) { + Decoration *deco = emerge->decorations[i]; + deco->placeDeco(this, blockseed + i, node_min, node_max); + } + for (size_t i = 0; i != emerge->ores.size(); i++) { Ore *ore = emerge->ores[i]; ore->placeOre(this, blockseed + i, node_min, node_max); diff --git a/src/mapgen_v7.h b/src/mapgen_v7.h index b6b03689d..d7177862d 100644 --- a/src/mapgen_v7.h +++ b/src/mapgen_v7.h @@ -67,9 +67,7 @@ public: v3s16 full_node_min; v3s16 full_node_max; - s16 *heightmap; s16 *ridge_heightmap; - u8 *biomemap; Noise *noise_terrain_base; Noise *noise_terrain_alt; diff --git a/src/script/lua_api/luaapi.cpp b/src/script/lua_api/luaapi.cpp index 180a44b26..75139861b 100644 --- a/src/script/lua_api/luaapi.cpp +++ b/src/script/lua_api/luaapi.cpp @@ -43,6 +43,14 @@ struct EnumString ModApiBasic::es_OreType[] = {0, NULL}, }; +struct EnumString ModApiBasic::es_DecorationType[] = +{ + {DECO_SIMPLE, "simple"}, + {DECO_SCHEMATIC, "schematic"}, + {DECO_LSYSTEM, "lsystem"}, + {0, NULL}, +}; + ModApiBasic::ModApiBasic() : ModApiBase() { } @@ -92,6 +100,7 @@ bool ModApiBasic::Initialize(lua_State* L,int top) { retval &= API_FCT(rollback_revert_actions_by); retval &= API_FCT(register_ore); + retval &= API_FCT(register_decoration); return retval; } @@ -162,21 +171,21 @@ int ModApiBasic::l_register_biome(lua_State *L) } enum BiomeTerrainType terrain = (BiomeTerrainType)getenumfield(L, index, - "terrain_type", es_BiomeTerrainType, BIOME_TERRAIN_NORMAL); + "terrain_type", es_BiomeTerrainType, BIOME_TERRAIN_NORMAL); Biome *b = bmgr->createBiome(terrain); - b->name = getstringfield_default(L, index, "name", ""); - b->top_nodename = getstringfield_default(L, index, "top_node", ""); - b->top_depth = getintfield_default(L, index, "top_depth", 0); + b->name = getstringfield_default(L, index, "name", ""); + b->top_nodename = getstringfield_default(L, index, "top_node", ""); + b->top_depth = getintfield_default(L, index, "top_depth", 0); b->filler_nodename = getstringfield_default(L, index, "filler_node", ""); - b->filler_height = getintfield_default(L, index, "filler_height", 0); - b->height_min = getintfield_default(L, index, "height_min", 0); - b->height_max = getintfield_default(L, index, "height_max", 0); - b->heat_point = getfloatfield_default(L, index, "heat_point", 0.); - b->humidity_point = getfloatfield_default(L, index, "humidity_point", 0.); - - b->flags = 0; //reserved - b->c_top = CONTENT_IGNORE; + b->filler_height = getintfield_default(L, index, "filler_height", 0); + b->height_min = getintfield_default(L, index, "height_min", 0); + b->height_max = getintfield_default(L, index, "height_max", 0); + b->heat_point = getfloatfield_default(L, index, "heat_point", 0.); + b->humidity_point = getfloatfield_default(L, index, "humidity_point", 0.); + + b->flags = 0; //reserved + b->c_top = CONTENT_IGNORE; b->c_filler = CONTENT_IGNORE; verbosestream << "register_biome: " << b->name << std::endl; bmgr->addBiome(b); @@ -184,8 +193,6 @@ int ModApiBasic::l_register_biome(lua_State *L) return 0; } - - // setting_set(name, value) int ModApiBasic::l_setting_set(lua_State *L) { @@ -650,4 +657,111 @@ int ModApiBasic::l_register_ore(lua_State *L) return 0; } +// register_decoration({lots of stuff}) +int ModApiBasic::l_register_decoration(lua_State *L) +{ + int index = 1; + luaL_checktype(L, index, LUA_TTABLE); + + EmergeManager *emerge = getServer(L)->getEmergeManager(); + BiomeDefManager *bdef = emerge->biomedef; + + enum DecorationType decotype = (DecorationType)getenumfield(L, index, + "deco_type", es_DecorationType, -1); + if (decotype == -1) { + errorstream << "register_decoration: unrecognized " + "decoration placement type"; + return 0; + } + + Decoration *deco = createDecoration(decotype); + if (!deco) { + errorstream << "register_decoration: decoration placement type " + << decotype << " not implemented"; + return 0; + } + + deco->c_place_on = CONTENT_IGNORE; + deco->place_on_name = getstringfield_default(L, index, "place_on", "ignore"); + deco->divlen = getintfield_default(L, index, "divlen", 8); + deco->fill_ratio = getfloatfield_default(L, index, "fill_ratio", 0.02); + + lua_getfield(L, index, "noise_params"); + deco->np = read_noiseparams(L, -1); + lua_pop(L, 1); + + lua_getfield(L, index, "biomes"); + if (lua_istable(L, -1)) { + lua_pushnil(L); + while (lua_next(L, -2)) { + const char *s = lua_tostring(L, -1); + u8 biomeid = bdef->getBiomeIdByName(s); + if (biomeid) + deco->biomes.insert(biomeid); + + lua_pop(L, 1); + } + lua_pop(L, 1); + } + + switch (decotype) { + case DECO_SIMPLE: { + DecoSimple *dsimple = (DecoSimple *)deco; + dsimple->c_deco = CONTENT_IGNORE; + dsimple->c_spawnby = CONTENT_IGNORE; + dsimple->spawnby_name = getstringfield_default(L, index, "spawn_by", "air"); + dsimple->deco_height = getintfield_default(L, index, "height", 1); + dsimple->deco_height_max = getintfield_default(L, index, "height_max", 0); + dsimple->nspawnby = getintfield_default(L, index, "num_spawn_by", -1); + + lua_getfield(L, index, "decoration"); + if (lua_istable(L, -1)) { + lua_pushnil(L); + while (lua_next(L, -2)) { + const char *s = lua_tostring(L, -1); + std::string str(s); + dsimple->decolist_names.push_back(str); + + lua_pop(L, 1); + } + } else if (lua_isstring(L, -1)) { + dsimple->deco_name = std::string(lua_tostring(L, -1)); + } else { + dsimple->deco_name = std::string("air"); + } + lua_pop(L, 1); + + if (dsimple->deco_height <= 0) { + errorstream << "register_decoration: simple decoration height" + " must be greater than 0" << std::endl; + delete dsimple; + return 0; + } + + break; } + case DECO_SCHEMATIC: { + //DecoSchematic *decoschematic = (DecoSchematic *)deco; + + break; } + case DECO_LSYSTEM: { + //DecoLSystem *decolsystem = (DecoLSystem *)deco; + + break; } + } + + if (deco->divlen <= 0) { + errorstream << "register_decoration: divlen must be " + "greater than 0" << std::endl; + delete deco; + return 0; + } + + emerge->decorations.push_back(deco); + + verbosestream << "register_decoration: decoration '" << deco->getName() + << "' registered" << std::endl; + return 0; +} + + ModApiBasic modapibasic_prototype; diff --git a/src/script/lua_api/luaapi.h b/src/script/lua_api/luaapi.h index 9623502c2..d03c14117 100644 --- a/src/script/lua_api/luaapi.h +++ b/src/script/lua_api/luaapi.h @@ -45,9 +45,6 @@ private: // get_server_status() static int l_get_server_status(lua_State *L); - // register_biome_groups({frequencies}) - static int l_register_biome_groups(lua_State *L); - // register_biome({lots of stuff}) static int l_register_biome(lua_State *L); @@ -130,9 +127,15 @@ private: // rollback_revert_actions_by(actor, seconds) -> bool, log messages static int l_rollback_revert_actions_by(lua_State *L); + // register_ore(oredesc) static int l_register_ore(lua_State *L); + + // register_decoration(deco) + static int l_register_decoration(lua_State *L); static struct EnumString es_OreType[]; + static struct EnumString es_DecorationType[]; + }; -- cgit v1.2.3 From 56093b6614a47b181bbce6d4e35d213a4e04120c Mon Sep 17 00:00:00 2001 From: kwolekr Date: Mon, 17 Jun 2013 18:23:31 -0400 Subject: Decoration: Change divlen to sidelen --- doc/lua_api.txt | 5 +++-- src/mapgen.cpp | 10 ++++++++-- src/mapgen.h | 2 +- src/script/lua_api/luaapi.cpp | 6 +++--- 4 files changed, 15 insertions(+), 8 deletions(-) (limited to 'src/script/lua_api') diff --git a/doc/lua_api.txt b/doc/lua_api.txt index b6981582e..85f6ca5a6 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -1875,8 +1875,9 @@ Decoration definition (register_decoration) deco_type = "simple", -- See "Decoration types" place_on = "default:dirt_with_grass", ^ Node that decoration can be placed on - divlen = 8, - ^ Number of divisions made in the chunk being generated + sidelen = 8, + ^ Size of divisions made in the chunk being generated. + ^ If the chunk size is not evenly divisible by sidelen, sidelen is made equal to the chunk size. fill_ratio = 0.02, ^ Ratio of the area to be uniformly filled by the decoration. ^ Used only if noise_params is not specified. diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 49ac827e1..17afcf350 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -232,8 +232,14 @@ void Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) { int carea_size = nmax.X - nmin.X + 1; // Divide area into parts - s16 sidelen = carea_size / divlen; - float area = sidelen * sidelen; + if (carea_size % sidelen) { + errorstream << "Decoration::placeDeco: chunk size is not divisible by " + "sidelen; setting sidelen to " << carea_size << std::endl; + sidelen = carea_size; + } + + s16 divlen = carea_size / sidelen; + int area = sidelen * sidelen; for (s16 z0 = 0; z0 < divlen; z0++) for (s16 x0 = 0; x0 < divlen; x0++) { diff --git a/src/mapgen.h b/src/mapgen.h index e8252cbbf..f3d90a14e 100644 --- a/src/mapgen.h +++ b/src/mapgen.h @@ -199,7 +199,7 @@ public: int mapseed; std::string place_on_name; content_t c_place_on; - s16 divlen; + s16 sidelen; float fill_ratio; NoiseParams *np; diff --git a/src/script/lua_api/luaapi.cpp b/src/script/lua_api/luaapi.cpp index 75139861b..667a3afcf 100644 --- a/src/script/lua_api/luaapi.cpp +++ b/src/script/lua_api/luaapi.cpp @@ -683,7 +683,7 @@ int ModApiBasic::l_register_decoration(lua_State *L) deco->c_place_on = CONTENT_IGNORE; deco->place_on_name = getstringfield_default(L, index, "place_on", "ignore"); - deco->divlen = getintfield_default(L, index, "divlen", 8); + deco->sidelen = getintfield_default(L, index, "sidelen", 8); deco->fill_ratio = getfloatfield_default(L, index, "fill_ratio", 0.02); lua_getfield(L, index, "noise_params"); @@ -749,8 +749,8 @@ int ModApiBasic::l_register_decoration(lua_State *L) break; } } - if (deco->divlen <= 0) { - errorstream << "register_decoration: divlen must be " + if (deco->sidelen <= 0) { + errorstream << "register_decoration: sidelen must be " "greater than 0" << std::endl; delete deco; return 0; -- cgit v1.2.3 From 53066024f6a91d5f83241b379b94d8557d43a646 Mon Sep 17 00:00:00 2001 From: PilzAdam Date: Wed, 19 Jun 2013 14:30:22 +0000 Subject: Add drowning --- doc/lua_api.txt | 1 + games/minimal/mods/default/textures/bubble.png | Bin 0 -> 273 bytes src/client.cpp | 7 +++++ src/client.h | 1 + src/environment.cpp | 40 ++++++++++++++++++++++++- src/environment.h | 2 ++ src/game.cpp | 2 +- src/hud.cpp | 5 +++- src/hud.h | 3 +- src/nodedef.cpp | 3 ++ src/nodedef.h | 1 + src/player.cpp | 4 ++- src/player.h | 1 + src/script/common/c_content.cpp | 1 + src/script/lua_api/l_object.cpp | 1 + 15 files changed, 67 insertions(+), 5 deletions(-) create mode 100644 games/minimal/mods/default/textures/bubble.png (limited to 'src/script/lua_api') diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 85f6ca5a6..d3d427d69 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -1710,6 +1710,7 @@ Node definition (register_node) liquid_alternative_source = "", -- Source version of flowing liquid liquid_viscosity = 0, -- Higher viscosity = slower flow (max. 7) liquid_renewable = true, -- Can new liquid source be created by placing + drowning = true, -- Player will drown in these two or more sources nearly? light_source = 0, -- Amount of light emitted by node damage_per_second = 0, -- If player is inside node, this damage is caused diff --git a/games/minimal/mods/default/textures/bubble.png b/games/minimal/mods/default/textures/bubble.png new file mode 100644 index 000000000..3bca7e11c Binary files /dev/null and b/games/minimal/mods/default/textures/bubble.png differ diff --git a/src/client.cpp b/src/client.cpp index 6b1789fe0..5f53e14f7 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -2680,6 +2680,13 @@ u16 Client::getHP() return player->hp; } +u16 Client::getBreath() +{ + Player *player = m_env.getLocalPlayer(); + assert(player != NULL); + return player->breath; +} + bool Client::getChatMessage(std::wstring &message) { if(m_chat_queue.size() == 0) diff --git a/src/client.h b/src/client.h index f0cc55868..1d231a5a3 100644 --- a/src/client.h +++ b/src/client.h @@ -349,6 +349,7 @@ public: void setCrack(int level, v3s16 pos); u16 getHP(); + u16 getBreath(); bool checkPrivilege(const std::string &priv) { return (m_privileges.count(priv) != 0); } diff --git a/src/environment.cpp b/src/environment.cpp index a97a9bd08..99da5190c 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -2227,7 +2227,45 @@ void ClientEnvironment::step(float dtime) damageLocalPlayer(damage_per_second, true); } } - + + /* + Drowning + */ + if(m_drowning_interval.step(dtime, 2.0)) + { + v3f pf = lplayer->getPosition(); + + // head + v3s16 p = floatToInt(pf + v3f(0, BS*1.6, 0), BS); + MapNode n = m_map->getNodeNoEx(p); + ContentFeatures c = m_gamedef->ndef()->get(n); + + if(c.isLiquid() && c.drowning){ + if(lplayer->breath > 10) + lplayer->breath = 11; + if(lplayer->breath > 0) + lplayer->breath -= 1; + } + + if(lplayer->breath == 0){ + damageLocalPlayer(1, true); + } + } + if(m_breathing_interval.step(dtime, 0.5)) + { + v3f pf = lplayer->getPosition(); + + // head + v3s16 p = floatToInt(pf + v3f(0, BS*1.6, 0), BS); + MapNode n = m_map->getNodeNoEx(p); + ContentFeatures c = m_gamedef->ndef()->get(n); + + if(!c.isLiquid() || !c.drowning){ + if(lplayer->breath <= 10) + lplayer->breath += 1; + } + } + /* Stuff that can be done in an arbitarily large dtime */ diff --git a/src/environment.h b/src/environment.h index a62173a11..ac479999c 100644 --- a/src/environment.h +++ b/src/environment.h @@ -494,6 +494,8 @@ private: Queue m_client_event_queue; IntervalLimiter m_active_object_light_update_interval; IntervalLimiter m_lava_hurt_interval; + IntervalLimiter m_drowning_interval; + IntervalLimiter m_breathing_interval; std::list m_player_names; }; diff --git a/src/game.cpp b/src/game.cpp index 30d9c7faf..88be47b39 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -3310,7 +3310,7 @@ void the_game( if (show_hud) { hud.drawHotbar(v2s32(displaycenter.X, screensize.Y), - client.getHP(), client.getPlayerItem()); + client.getHP(), client.getPlayerItem(), client.getBreath()); } /* diff --git a/src/hud.cpp b/src/hud.cpp index a3ae38bcb..9404ed997 100644 --- a/src/hud.cpp +++ b/src/hud.cpp @@ -278,7 +278,7 @@ void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, std::string texture, s } -void Hud::drawHotbar(v2s32 centerlowerpos, s32 halfheartcount, u16 playeritem) { +void Hud::drawHotbar(v2s32 centerlowerpos, s32 halfheartcount, u16 playeritem, s32 breath) { InventoryList *mainlist = inventory->getList("main"); if (mainlist == NULL) { errorstream << "draw_hotbar(): mainlist == NULL" << std::endl; @@ -295,6 +295,9 @@ void Hud::drawHotbar(v2s32 centerlowerpos, s32 halfheartcount, u16 playeritem) { if (player->hud_flags & HUD_FLAG_HEALTHBAR_VISIBLE) drawStatbar(pos - v2s32(0, 4), HUD_CORNER_LOWER, HUD_DIR_LEFT_RIGHT, "heart.png", halfheartcount, v2s32(0, 0)); + if (player->hud_flags & HUD_FLAG_BREATHBAR_VISIBLE && breath <= 10) + drawStatbar(pos - v2s32(-180, 4), HUD_CORNER_LOWER, HUD_DIR_LEFT_RIGHT, + "bubble.png", breath*2, v2s32(0, 0)); } diff --git a/src/hud.h b/src/hud.h index fa9d33f8b..c7289f7c4 100644 --- a/src/hud.h +++ b/src/hud.h @@ -35,6 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #define HUD_FLAG_HEALTHBAR_VISIBLE (1 << 1) #define HUD_FLAG_CROSSHAIR_VISIBLE (1 << 2) #define HUD_FLAG_WIELDITEM_VISIBLE (1 << 3) +#define HUD_FLAG_BREATHBAR_VISIBLE (1 << 4) #define HUD_PARAM_HOTBAR_ITEMCOUNT 1 @@ -122,7 +123,7 @@ public: void drawStatbar(v2s32 pos, u16 corner, u16 drawdir, std::string texture, s32 count, v2s32 offset); - void drawHotbar(v2s32 centerlowerpos, s32 halfheartcount, u16 playeritem); + void drawHotbar(v2s32 centerlowerpos, s32 halfheartcount, u16 playeritem, s32 breath); void resizeHotbar(); void drawCrosshair(); diff --git a/src/nodedef.cpp b/src/nodedef.cpp index ba3e42e98..7d8ce70d3 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -211,6 +211,7 @@ void ContentFeatures::reset() liquid_alternative_source = ""; liquid_viscosity = 0; liquid_renewable = true; + drowning = true; light_source = 0; damage_per_second = 0; node_box = NodeBox(); @@ -279,6 +280,7 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) writeU8(os, rightclickable); // Stuff below should be moved to correct place in a version that otherwise changes // the protocol version + writeU8(os, drowning); } void ContentFeatures::deSerialize(std::istream &is) @@ -343,6 +345,7 @@ void ContentFeatures::deSerialize(std::istream &is) try{ // Stuff below should be moved to correct place in a version that // otherwise changes the protocol version + drowning = readU8(is); }catch(SerializationError &e) {}; } diff --git a/src/nodedef.h b/src/nodedef.h index 2691aca33..e397d20e0 100644 --- a/src/nodedef.h +++ b/src/nodedef.h @@ -219,6 +219,7 @@ struct ContentFeatures u8 liquid_viscosity; // Is liquid renewable (new liquid source will be created between 2 existing) bool liquid_renewable; + bool drowning; // Amount of light the node emits u8 light_source; u32 damage_per_second; diff --git a/src/player.cpp b/src/player.cpp index 4eb5955c0..a199c9a6c 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -36,6 +36,7 @@ Player::Player(IGameDef *gamedef): camera_barely_in_ceiling(false), inventory(gamedef->idef()), hp(PLAYER_MAX_HP), + breath(-1), peer_id(PEER_ID_INEXISTENT), // protected m_gamedef(gamedef), @@ -80,7 +81,8 @@ Player::Player(IGameDef *gamedef): physics_override_gravity = 1; hud_flags = HUD_FLAG_HOTBAR_VISIBLE | HUD_FLAG_HEALTHBAR_VISIBLE | - HUD_FLAG_CROSSHAIR_VISIBLE | HUD_FLAG_WIELDITEM_VISIBLE; + HUD_FLAG_CROSSHAIR_VISIBLE | HUD_FLAG_WIELDITEM_VISIBLE | + HUD_FLAG_BREATHBAR_VISIBLE; hud_hotbar_itemcount = HUD_HOTBAR_ITEMCOUNT_DEFAULT; } diff --git a/src/player.h b/src/player.h index d3738fd52..517bd354d 100644 --- a/src/player.h +++ b/src/player.h @@ -232,6 +232,7 @@ public: float physics_override_gravity; u16 hp; + u16 breath; float hurt_tilt_timer; float hurt_tilt_strength; diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp index c7966a0be..64c76ef7c 100644 --- a/src/script/common/c_content.cpp +++ b/src/script/common/c_content.cpp @@ -389,6 +389,7 @@ ContentFeatures read_content_features(lua_State *L, int index) f.liquid_viscosity = getintfield_default(L, index, "liquid_viscosity", f.liquid_viscosity); getboolfield(L, index, "liquid_renewable", f.liquid_renewable); + getboolfield(L, index, "drowning", f.drowning); // Amount of light the node emits f.light_source = getintfield_default(L, index, "light_source", f.light_source); diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index 1e45610a6..f90b59285 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -62,6 +62,7 @@ struct EnumString es_HudBuiltinElement[] = {HUD_FLAG_HEALTHBAR_VISIBLE, "healthbar"}, {HUD_FLAG_CROSSHAIR_VISIBLE, "crosshair"}, {HUD_FLAG_WIELDITEM_VISIBLE, "wielditem"}, + {HUD_FLAG_BREATHBAR_VISIBLE, "breathbar"}, {0, NULL}, }; -- cgit v1.2.3 From c2cdaceed0d43317d8e8d431052854fe72d8fddf Mon Sep 17 00:00:00 2001 From: Kahrl Date: Fri, 21 Jun 2013 00:04:18 +0200 Subject: Make minetest.debug accept multiple parameters; convert them to string --- src/script/lua_api/luaapi.cpp | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) (limited to 'src/script/lua_api') diff --git a/src/script/lua_api/luaapi.cpp b/src/script/lua_api/luaapi.cpp index 667a3afcf..e19c90952 100644 --- a/src/script/lua_api/luaapi.cpp +++ b/src/script/lua_api/luaapi.cpp @@ -105,13 +105,31 @@ bool ModApiBasic::Initialize(lua_State* L,int top) { return retval; } -// debug(text) +// debug(...) // Writes a line to dstream int ModApiBasic::l_debug(lua_State *L) { NO_MAP_LOCK_REQUIRED; - std::string text = lua_tostring(L, 1); - dstream << text << std::endl; + // Handle multiple parameters to behave like standard lua print() + int n = lua_gettop(L); + lua_getglobal(L, "tostring"); + for(int i = 1; i <= n; i++){ + /* + Call tostring(i-th argument). + This is what print() does, and it behaves a bit + differently from directly calling lua_tostring. + */ + lua_pushvalue(L, -1); /* function to be called */ + lua_pushvalue(L, i); /* value to print */ + lua_call(L, 1, 1); + const char *s = lua_tostring(L, -1); + if(i>1) + dstream << "\t"; + if(s) + dstream << s; + lua_pop(L, 1); + } + dstream << std::endl; return 0; } -- cgit v1.2.3