From 6251b0f4b166560bbfe70215ee54d10cbba2ed09 Mon Sep 17 00:00:00 2001 From: srifqi Date: Sun, 24 Aug 2014 19:53:47 +0700 Subject: [PATCH] Fork from amg. Add initial development files. Change a little bit, see README. --- README.md | 26 ++ biome.lua | 350 ++++++++++++++++++++++++ biomemgr.lua | 52 ++++ depends.txt | 2 + hud.lua | 52 ++++ init.lua | 226 ++++++++++++++++ nodes.lua | 17 ++ textures/amgmt_savanna_grass.png | Bin 0 -> 3442 bytes textures/amgmt_savanna_grass_side.png | Bin 0 -> 3300 bytes trees.lua | 365 ++++++++++++++++++++++++++ 10 files changed, 1090 insertions(+) create mode 100644 README.md create mode 100644 biome.lua create mode 100644 biomemgr.lua create mode 100644 depends.txt create mode 100644 hud.lua create mode 100644 init.lua create mode 100644 nodes.lua create mode 100644 textures/amgmt_savanna_grass.png create mode 100644 textures/amgmt_savanna_grass_side.png create mode 100644 trees.lua diff --git a/README.md b/README.md new file mode 100644 index 0000000..652420b --- /dev/null +++ b/README.md @@ -0,0 +1,26 @@ +amgmt +===== + +Another Map Generator mod for Minetest (fork from amg) + +Still experimental! + + +##Feature +- 12 biome +- Biomes, Trees, Nodes, etc. are modifyable +- Experimental water lakes! + +##List of Biomes +- Ice Plains +- Ice Plains Spikes +- Cold Taiga +- Stone Plain +- Extreme Hills +- Taiga +- Plains +- Flower Plains +- River +- Forest +- Savanna +- Desert diff --git a/biome.lua b/biome.lua new file mode 100644 index 0000000..faeedfa --- /dev/null +++ b/biome.lua @@ -0,0 +1,350 @@ +biome = biome or {} +local gci = minetest.get_content_id +local badd = biome.add + +-- node id? +local c_air = gci("air") +local c_water = gci("default:water_source") +local c_ice = gci("default:ice") +local c_stone = gci("default:stone") +local c_dirt = gci("default:dirt") +local c_dirt_grass = gci("default:dirt_with_grass") +local c_dirt_snow = gci("default:dirt_with_snow") +local c_sand = gci("default:sand") +local c_sandstone = gci("default:sandstone") + +local c_dirt_savanna = gci("amgmt:dirt_at_savanna") + +--listing biome from cold to hot +-- cold +badd({ + name = "Ice Plains", + mint = 0, + maxt = 0.2, + minh = 0, + maxh = 50, + trees = {{"pine",225}}, + get_block = function(temp, humi, base, wl, y) + if y > base and y > wl then + return c_air + elseif y > base and y <= wl then + if base < wl - 1 then + return c_water + elseif base < wl then + return c_ice + elseif base >= wl then + return c_air + end + elseif y < base - 2 then + return c_stone + elseif y < base and y > base - 3 then + return c_dirt + else + if y < wl then + return c_dirt + else + return c_dirt_snow + end + end + end +}) +badd({ + name = "Ice Plains Spikes", + mint = 0, + maxt = 0.2, + minh = 50, + maxh = 100, + trees = {{"ice_spike",25}}, + get_block = function(temp, humi, base, wl, y) + if y > base and y > wl then + return c_air + elseif y > base and y <= wl then + if base < wl - 1 then + return c_water + elseif base < wl then + return c_ice + elseif base >= wl then + return c_air + end + elseif y < base - 2 then + return c_stone + elseif y < base and y > base - 3 then + return c_dirt + else + if y < wl then + return c_dirt + else + return c_dirt_snow + end + end + end +}) +badd({ + name = "Cold Taiga", + mint = 0.2, + maxt = 0.4, + trees = {{"pine_cold",25}}, + get_block = function(temp, humi, base, wl, y) + if y > base and y > wl then + return c_air + elseif y > base and y <= wl then + if base < wl - 1 then + return c_water + elseif base < wl then + return c_ice + elseif base >= wl then + return c_air + end + elseif y < base - 2 then + return c_stone + elseif y < base and y > base - 3 then + return c_dirt + else + if y < wl then + return c_dirt + else + return c_dirt_snow + end + end + end +}) +badd({ + name = "Stone Plain", + mint = 0.4, + maxt = 0.5, + get_block = function(temp, humi, base, wl, y) + if y > base and y > wl then + return c_air + elseif y > base and y <= wl then + if base < wl then + return c_water + elseif base >= wl then + return c_air + end + elseif y <= base then + return c_stone + end + end +}) +badd({ + name = "Extreme Hills", + mint = 0.5, + maxt = 0.7, + trees = {{"grass14",30}}, + get_block = function(temp, humi, base_, wl, y) + local base = base_ + math.ceil(math.abs(base_ - wl) * 2/5) + if y > base and y > wl then + return c_air + elseif y > base and y <= wl then + if base < wl then + return c_water + elseif base >= wl then + return c_air + end + elseif y < base - 2 then + return c_stone + elseif y < base and y > base - 3 then + return c_dirt + else + if y < wl then + return c_dirt + elseif y >= 95 then + return c_dirt_snow + else + return c_dirt_grass + end + end + end +}) +badd({ + name = "Taiga", + mint = 0.7, + maxt = 0.9, + trees = {{"pine_taiga",25}}, + get_block = function(temp, humi, base, wl, y) + if y > base and y > wl then + return c_air + elseif y > base and y <= wl then + if base < wl then + return c_water + elseif base >= wl then + return c_air + end + elseif y < base - 2 then + return c_stone + elseif y < base and y > base - 3 then + return c_dirt + else + if y < wl then + return c_dirt + else + return c_dirt_grass + end + end + end +}) +-- medium/lush +badd({ + name = "Plains", + mint = 0.9, + maxt = 1.15, + minh = 0, + maxh = 50, + trees = {{"grass14",30}, {"grass35",5},{"papyrus",15},{"flowers",15}}, + get_block = function(temp, humi, base, wl, y) + if y > base and y > wl then + return c_air + elseif y > base and y <= wl then + if base < wl then + return c_water + elseif base >= wl then + return c_air + end + elseif y < base - 2 then + return c_stone + elseif y < base and y > base - 3 then + return c_dirt + else + if y < wl then + return c_dirt + else + if temp > 1 and (base == wl or base == wl+1) then + return c_sand + else + return c_dirt_grass + end + end + end + end +}) +badd({ + name = "Flower Plains", + mint = 0.9, + maxt = 1.15, + minh = 50, + maxh = 100, + trees = {{"flowers",5},{"flowers",5},{"flowers",5}}, + get_block = function(temp, humi, base, wl, y) + if y > base and y > wl then + return c_air + elseif y > base and y <= wl then + if base < wl then + return c_water + elseif base >= wl then + return c_air + end + elseif y < base - 2 then + return c_stone + elseif y < base and y > base - 3 then + return c_dirt + else + if y < wl then + return c_dirt + else + return c_dirt_grass + end + end + end +}) +badd({ + name = "River", + mint = 1.15, + maxt = 1.25, + get_block = function(temp, humi, base_, wl, y) + local base = wl - math.ceil(math.abs(base_ - wl) * 1/3) - 1 + if y > base and y > wl then + return c_air + elseif y > base and y <= wl then + return c_water + elseif y < base - 2 then + return c_stone + elseif y < base and y > base - 3 then + return c_sandstone + else + return c_sand + end + end +}) +badd({ + name = "Forest", + mint = 1.25, + maxt = 1.5, + trees = {{"normal",15},{"grass14",60},{"grass35",5},{"papyrus",15},{"flowers",15}}, + get_block = function(temp, humi, base, wl, y) + if y > base and y > wl then + return c_air + elseif y > base and y <= wl then + if base < wl then + return c_water + elseif base >= wl then + return c_air + end + elseif y < base - 2 then + return c_stone + elseif y < base and y > base - 3 then + return c_dirt + else + if y < wl then + return c_dirt + else + return c_dirt_grass + end + end + end +}) +-- dry +badd({ + name = "Savanna", + mint = 1.5, + maxt = 1.75, + trees = {{"savanna",225},{"grass35",5}}, + get_block = function(temp, humi, base, wl, y) + if y > base and y > wl then + return c_air + elseif y > base and y <= wl then + if base < wl then + return c_water + elseif base >= wl then + return c_air + end + elseif y < base - 2 then + return c_stone + elseif y < base and y > base - 3 then + return c_dirt + else + if y < wl then + return c_dirt + else + if temp > 1.7 and base == wl then + return c_sand + else + return c_dirt_savanna + end + end + end + end +}) +-- hot +badd({ + name = "Desert", + mint = 1.75, + maxt = 2, + trees = {{"cactus",50},{"dry_shrub",50}}, + get_block = function(temp, humi, base, wl, y) + if y > base and y > wl then + return c_air + elseif y > base and y <= wl then + if base < wl then + return c_water + elseif base >= wl then + return c_air + end + elseif y < base - 2 then + return c_sandstone + elseif y < base and y > base - 3 then + return c_sand + else + return c_sand + end + end +}) \ No newline at end of file diff --git a/biomemgr.lua b/biomemgr.lua new file mode 100644 index 0000000..01fff3f --- /dev/null +++ b/biomemgr.lua @@ -0,0 +1,52 @@ +biome = biome or {} + +biome.list = {} +function biome.add(p) + biome.list[#biome.list+1] = { + name = p.name, + mint = p.mint, -- min temperature + maxt = p.maxt, -- max + minh = p.minh or 0, -- min humidity + maxh = p.maxh or 100, -- max + trees = p.trees or {{"nil",1024}}, + get_block = p.get_block + } +end + +-- testing purpose only! +biome.add({ + name = "NIL (Biome?)", + mint = -5, + maxt = -3, + get_block = function() return minetest.get_content_id("air") end +}) +--]] + +function biome.get_by_temp_humi(t,h) + t = math.min(t, 2) + h = math.min(h, 100) + local bl = biome.list + local found = {} + for i = 1, #bl do + if t >= bl[i].mint and t <= bl[i].maxt then + found[#found+1] = {i,bl[i].name} + end + end + for i = 1, #found do + local u = found[i][1] + local o = found[i][2] + if h >= bl[u].minh and h <= bl[u].maxh then + return {u,bl[u].name} + end + end + return {0,"NIL (Biome?)"} +end + +function biome.get_block_by_temp_humi(temp,humi,base,wl,y,x,z) + temp = math.min(temp, 2) + humi = math.min(humi, 100) + base = math.min(base, 255) + return biome.list[biome.get_by_temp_humi(temp,humi)[1]].get_block(temp,humi,base,wl,y,x,z) or 0 +end + +dofile(minetest.get_modpath(minetest.get_current_modname()).."/biome.lua") \ No newline at end of file diff --git a/depends.txt b/depends.txt new file mode 100644 index 0000000..df07aca --- /dev/null +++ b/depends.txt @@ -0,0 +1,2 @@ +default +flowers \ No newline at end of file diff --git a/hud.lua b/hud.lua new file mode 100644 index 0000000..1ed091d --- /dev/null +++ b/hud.lua @@ -0,0 +1,52 @@ +amgmt.hud = {} + +local bedrock_timer = 0 +minetest.register_globalstep(function(dtime) + if dtime < 0.1 then return end + for _,player in ipairs(minetest.get_connected_players()) do + local pos = player:getpos() + local name = player:get_player_name() + + local base = minetest.get_perlin(np.b.s, np.b.o, np.b.p, np.b.c):get2d({x=pos.x,y=pos.z}) + local moun = minetest.get_perlin(np.m.s, np.m.o, np.m.p, np.m.c):get2d({x=pos.x,y=pos.z}) + local base = math.ceil((base * -30) + wl + 10 + (moun * 15)) + local temp = 0 + local humi = 0 + if base > 95 then + temp = 0.05 + humi = 0.9 + else + temp = minetest.get_perlin(np.t.s, np.t.o, np.t.p, np.t.c):get2d({x=pos.x,y=pos.z}) + humi = minetest.get_perlin(np.h.s, np.h.o, np.h.p, np.h.c):get2d({x=pos.x,y=pos.z}) + end + + local biometext = biome.get_by_temp_humi(math.abs(temp*2),math.abs(humi*100))[2] + + if not amgmt.hud[name] then + amgmt.hud[name] = {} + + amgmt.hud[name].BiomeId = player:hud_add({ + hud_elem_type = "text", + name = "Biome", + number = 0xFFFFFF, + position = {x=0, y=0.5}, + offset = {x=13, y=-20}, + direction = 0, + text = "Biome: "..biometext, + scale = {x=200, y=-60}, + alignment = {x=1, y=1}, + }) + + amgmt.hud[name].oldBiome = biometext + return + elseif amgmt.hud[name].oldBiome ~= biometext then + player:hud_change(amgmt.hud[name].BiomeId, "text", + "Biome: "..biometext) + amgmt.hud[name].oldBiome = biometext + end + end +end) + +minetest.register_on_leaveplayer(function(player) + amgmt.hud[player:get_player_name()] = nil +end) \ No newline at end of file diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..9b8786a --- /dev/null +++ b/init.lua @@ -0,0 +1,226 @@ +amgmt = amgmt or {} +amgmt.seed = nil + +minetest.register_on_mapgen_init(function(mgparams) + minetest.set_mapgen_params({mgname="singlenode"}) + amgmt.seed = mgparams.seed +end) + +--param? +wl = 0 +HMAX = 300 +HMIN = -6000 +BEDROCK = -5000 +BEDROCK2 = -6000 + +biome = {} +tree = {} +dofile(minetest.get_modpath(minetest.get_current_modname()).."/nodes.lua") +dofile(minetest.get_modpath(minetest.get_current_modname()).."/trees.lua") +dofile(minetest.get_modpath(minetest.get_current_modname()).."/biomemgr.lua") + +local function get_perlin_map(seed, octaves, persistance, scale, minp, maxp) + local sidelen = maxp.x - minp.x +1 + local pm = minetest.get_perlin_map( + {offset=0, scale=1, spread={x=scale, y=scale, z=scale}, seed=seed, octaves=octaves, persist=persistance}, + {x=sidelen, y=sidelen, z=sidelen} + ) + return pm:get2dMap_flat({x = minp.x, y = minp.z, z = 0}) +end + +-- noiseparam +np = { +-- s = seed, o = octaves, p = persistance, c = scale + b = {s = 1234, o = 6, p = 0.5, c = 512}, + m = {s = 4321, o = 6, p = 0.5, c = 256}, + t = {s = 5678, o = 7, p = 0.5, c = 512}, + h = {s = 8765, o = 7, p = 0.5, c = 512}, + s1 = {s = 125, o = 6, p = 0.5, c = 256}, +} + +--node id? +local gci = minetest.get_content_id +local c_air = gci("air") +local c_bedrock = gci("amgmt:bedrock") +local c_sand = gci("default:sand") +local c_sandstone = gci("default:sandstone") +local c_water = gci("default:water_source") +local c_lava_source = gci("default:lava_source") + +local function amgmt_generate(minp, maxp, seed, vm, emin, emax) + local t1 = os.clock() + local pr = PseudoRandom(seed) + print("[amgmt]:"..minp.x..","..minp.y..","..minp.z) + local area = VoxelArea:new{ + MinEdge={x=emin.x, y=emin.y, z=emin.z}, + MaxEdge={x=emax.x, y=emax.y, z=emax.z}, + } + local data = vm:get_data() + local sidelen = maxp.x - minp.x + 1 + local base = get_perlin_map(np.b.s, np.b.o, np.b.p, np.b.c, minp, maxp) -- base height + local moun = get_perlin_map(np.m.s, np.m.o, np.m.p, np.m.c, minp, maxp) -- addition + local temp = get_perlin_map(np.t.s, np.t.o, np.t.p, np.t.c, minp, maxp) -- temperature (0-2) + local humi = get_perlin_map(np.h.s, np.h.o, np.h.p, np.h.c, minp, maxp) -- humidity (0-100) + local spc1 = get_perlin_map(np.h.s, np.h.o, np.h.p, np.h.c, minp, maxp) -- special1 + local cave = minetest.get_perlin(3456, 6, 0.5, 360) -- cave + --local laca = minetest.get_perlin(1278, 6, 0.5, 360) -- lava cave + print("[amgmt]:terrain generation") + local nizx = 0 + for z = minp.z, maxp.z do + for x = minp.x, maxp.x do + nizx = nizx + 1 + local base_ = math.ceil((base[nizx] * -50) + wl + 16.67 + (moun[nizx] * 15)) + local temp_ = 0 + local humi_ = 0 + if base_ > 95 then + temp_ = 0.10 + humi_ = 90 + else + temp_ = math.abs(temp[nizx] * 2) + humi_ = math.abs(humi[nizx] * 100) + end + --print(x..","..z.." : "..temp_) + for y_ = minp.y, maxp.y do + local vi = area:index(x,y_,z) + -- world height limit :( + if y_ < HMIN or y_ > HMAX then + data[vi] = c_air + elseif y_ == BEDROCK or y_ == BEDROCK2 then + data[vi] = c_bedrock + -- + -- cave + elseif math.abs(cave:get3d({x=x,y=y_,z=z})) < 0.005 then + data[vi] = c_air + --]] + --[[ + -- lava cave + elseif math.abs(laca:get3d({x=x,y=y_,z=z})) > 350 and y_ < wl * 2/3 then + data[vi] = c_lava_source + --]] + -- biome + else + data[vi] = c_air + --data[vi] = biome.get_block_by_temp_humi(temp_, humi_, base_, wl, y_, x, z) + end + end + + end + end + + --forming lake + print("[amgmt]:forming lake") + local found_lake = false + local chulen = (maxp.x - minp.x + 1) / 16 + for cz = 0, chulen-1 do + for cx = 0, chulen-1 do + local nizx = 0 + for z = minp.z + cz*16, minp.z + (cz+1)*16 do + if found_lake == true then break end + for x = minp.x + cx*16, minp.x + (cx+1)*16 do + if found_lake == true then break end + nizx = nizx + 1 + local base_ = math.ceil((base[nizx] * -50) + wl + 16.67 + (moun[nizx] * 15)) + local lake_ = math.abs(spc1[nizx]) + if lake_ < 0.001 then + print("[amgmt] lake found! "..x..","..base_..","..z.."("..lake_..")") + found_lake = true + for u = -2, 2 do + for i = -2, 2 do + local vi = area:index(x+u,base_-2,z+i) + data[vi] = c_sandstone + for o = -1, 0 do + local vi = area:index(x+u,base_+o,z+i) + if u > -2 and u < 2 and i > -2 and i < 2 and o == 0 then + data[vi] = c_water + else + data[vi] = c_sand + end + end + end + end + + for ii = 1, 10 do + local xx = pr:next(-1,1) + local zz = pr:next(-1,1) + + local vi = area:index(x+xx,base_-1,z+zz) + data[vi] = c_water + end + end + end + end + end + end + + --ore generation + --print("[amgmt]:generating ore") + + --tree planting + print("[amgmt]:planting tree") + local nizx = 0 + for z = minp.z, maxp.z do + for x = minp.x, maxp.x do + nizx = nizx + 1 + local base_ = math.ceil((base[nizx] * -50) + wl + 16.67 + (moun[nizx] * 15)) + local temp_ = 0 + local humi_ = 0 + if base_ > 95 then + temp_ = 0.10 + humi_ = 90 + else + temp_ = math.abs(temp[nizx] * 2) + humi_ = math.abs(humi[nizx] * 100) + end + local biome__ = biome.list[biome.get_by_temp_humi(temp_,humi_)[1]] + local tr = biome__.trees + local filled = false + --print("done. "..biome__.name.." Biome. spawning "..#tr.." type of floras ...") + for i = 1, #tr do + if filled == true then break end + local tri = tree.registered[tr[i][1]] or tree.registered["nil"] + local chance = tr[i][2] or 1024 + --[[ + print( + "try to spawn "..tr[i][1].. + " at "..x..","..(base_+1)..","..z.. + " in "..biome__.name.." biome" + ) + --]] + if + pr:next(1,chance) == 1 and + base_+1 >= tri.minh and base_+1 <= tri.maxh and + data[area:index(x,base_,z)] == gci(tri.grows_on) + then + tree.spawn({x=x,y=base_+1,z=z},tr[i][1],data,area,seed,minp,maxp,pr) + filled = true + --[[ + print( + "spawned "..tr[i][1].. + " at "..x..","..(base_+1)..","..z.. + " in "..biome__.name.." biome" + ) + --]] + end + end + end + end + + print("[amgmt]:applying map data") + vm:set_data(data) + vm:set_lighting({day=0, night=0}) + vm:update_liquids() + vm:calc_lighting() + vm:write_to_map(data) + local chugent = math.ceil((os.clock() - t1) * 100000)/100 + print("[amgmt]:Done in "..chugent.."ms") +end + +minetest.register_on_generated(function(minp, maxp, seed) + if minp.y > HMAX or maxp.y < HMIN then return end + local vm, emin, emax = minetest.get_mapgen_object("voxelmanip") + amgmt_generate(minp, maxp, seed, vm, emin, emax) +end) + +dofile(minetest.get_modpath(minetest.get_current_modname()).."/hud.lua") + +print("[amgmt] (Another Map Generator for Minetest) Loaded") \ No newline at end of file diff --git a/nodes.lua b/nodes.lua new file mode 100644 index 0000000..49151d9 --- /dev/null +++ b/nodes.lua @@ -0,0 +1,17 @@ +minetest.register_node("amgmt:bedrock", { + description = "amgmt's BEDROCK", + tiles ={"default_cobble.png"}, + groups = {unbreakable = 1, not_in_creative_inventory = 1}, + sounds = default.node_sound_stone_defaults() +}) + +minetest.register_node("amgmt:dirt_at_savanna", { + description = "Dirt with Grass at Savanna", + tiles = {"amgmt_savanna_grass.png", "default_dirt.png", "default_dirt.png^amgmt_savanna_grass_side.png"}, + is_ground_content = true, + groups = {crumbly=3,soil=1}, + drop = 'default:dirt', + sounds = default.node_sound_dirt_defaults({ + footstep = {name="default_grass_footstep", gain=0.25}, + }), +}) \ No newline at end of file diff --git a/textures/amgmt_savanna_grass.png b/textures/amgmt_savanna_grass.png new file mode 100644 index 0000000000000000000000000000000000000000..a43fda006e3e16dd6074e179f906cddf94c362ba GIT binary patch literal 3442 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 ip+KTIln1{7fB^twb0K6>FLUw$0000