mirror of
https://github.com/luanti-org/minetest_game.git
synced 2025-07-13 09:51:53 -04:00
Added meseors
This commit is contained in:
parent
8b50e7bf3d
commit
32d9ba2ff9
5 changed files with 321 additions and 0 deletions
270
mods/meseor/init.lua
Normal file
270
mods/meseor/init.lua
Normal file
|
@ -0,0 +1,270 @@
|
|||
-- meseor 0.2.0 by paramat.
|
||||
-- License WTFPL, see license.txt.
|
||||
|
||||
-- Parameters.
|
||||
|
||||
local ONGEN = true -- (true / false) Enable / disable impacts on generated chunk.
|
||||
local ONGCHA = 9 -- 9 -- Ongen 1/x chance of impact per generated chunk.
|
||||
|
||||
local ABM = false -- Enable / disable impacts by abm on surface material.
|
||||
local ABMINT = 181 -- 181 -- Abm interval.
|
||||
local ABMCHA = 100000 -- 100000 -- Abm 1/x chance per node.
|
||||
local DAMAGE = true -- Enable / disable player damage loop.
|
||||
local DAMMAX = 20 -- 20 -- Maximum damage. 20 = direct hit is fatal.
|
||||
|
||||
local RADMIN = 3 -- 3 -- Minimum crater radius.
|
||||
local RADMAX = 31 -- 31 -- Maximum crater radius, on-gen craters are limited to 16.
|
||||
local STOCHA = 5 -- 5 -- 1/x chance of stone boulders instead of gravel.
|
||||
|
||||
local XMIN = -16000 -- Impact area dimensions. Impacts only inside this area.
|
||||
local XMAX = 16000
|
||||
local ZMIN = -16000
|
||||
local ZMAX = 16000
|
||||
|
||||
local SAXMIN = 0 -- Safe area dimensions. No impacts inside this area.
|
||||
local SAXMAX = 0 -- When overlapping impact area, the safe area overrides.
|
||||
local SAZMIN = 0
|
||||
local SAZMAX = 0
|
||||
|
||||
local DEBUG = true
|
||||
|
||||
-- Stuff.
|
||||
|
||||
meseor = {}
|
||||
|
||||
-- On generated.
|
||||
|
||||
if ONGEN then
|
||||
minetest.register_on_generated(function(minp, maxp, seed)
|
||||
if math.random(ONGCHA) == 2 then
|
||||
local env = minetest.env
|
||||
local maxrad = RADMAX
|
||||
if maxrad > 16 then maxrad = 16 end
|
||||
local conrad = math.random(RADMIN, maxrad)
|
||||
local rimrad = math.ceil(conrad * 2.4)
|
||||
local x = math.random(minp.x + rimrad, maxp.x - rimrad)
|
||||
local z = math.random(minp.z + rimrad, maxp.z - rimrad)
|
||||
-- Find surface with air above, abort if water found, ignore trees and ice.
|
||||
local surfy = false
|
||||
local aa = false
|
||||
for y = maxp.y, minp.y, -1 do
|
||||
local nodename = env:get_node({x=x,y=y,z=z}).name
|
||||
if nodename == "default:water_source" or nodename == "default:water_flowing" then
|
||||
return
|
||||
elseif nodename == "air" then
|
||||
aa = true
|
||||
elseif aa and nodename ~= "air" and nodename ~= "ignore" and nodename ~= "snow:ice"
|
||||
and nodename ~= "default:leaves" and nodename ~= "default:jungleleaves"
|
||||
and nodename ~= "default:tree" and nodename ~= "default:jungletree" then
|
||||
surfy = y
|
||||
break
|
||||
end
|
||||
end
|
||||
if not surfy then
|
||||
return
|
||||
end
|
||||
DAMAGE = false
|
||||
crater({x=x,y=surfy,z=z},conrad)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
-- Abm.
|
||||
|
||||
if ABM then
|
||||
minetest.register_abm({
|
||||
nodenames = {
|
||||
"default:obsidian",
|
||||
"moontest:dust",
|
||||
},
|
||||
interval = ABMINT,
|
||||
chance = ABMCHA,
|
||||
action = function(pos, node, _, _)
|
||||
local env = minetest.env
|
||||
local x = pos.x
|
||||
local y = pos.y
|
||||
local z = pos.z
|
||||
-- Find close surface above, abort if underwater or no close surface found.
|
||||
local surfy = false
|
||||
for j = 1, 4 do
|
||||
local nodename = env:get_node({x=x,y=y+j,z=z}).name
|
||||
if nodename == "default:water_source" or nodename == "default:water_flowing" then
|
||||
return
|
||||
elseif nodename == "air" then
|
||||
surfy = y+j-1
|
||||
break
|
||||
end
|
||||
end
|
||||
if not surfy then
|
||||
return
|
||||
end
|
||||
local conrad = math.random(RADMIN, RADMAX)
|
||||
crater({x=x,y=surfy,z=z},conrad)
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
-- Functions.
|
||||
|
||||
function crater(pos, conrad)
|
||||
local env = minetest.env
|
||||
local x = pos.x
|
||||
local y = pos.y
|
||||
local z = pos.z
|
||||
local rimrad = math.ceil(conrad * 2.4)
|
||||
-- If in safe zone or not in impact zone then abort.
|
||||
if (x > SAXMIN - rimrad and x < SAXMAX + rimrad and z > SAZMIN - rimrad and z < SAZMAX + rimrad)
|
||||
or not (x > XMIN and x < XMAX and z > ZMIN and z < ZMAX) then
|
||||
return
|
||||
end
|
||||
-- Check enough depth.
|
||||
for j = -conrad - 1, -1 do
|
||||
local nodename = env:get_node({x=x,y=y+j,z=z}).name
|
||||
if nodename == "air" or nodename == "ignore" then
|
||||
return
|
||||
end
|
||||
end
|
||||
-- Check pos open to sky.
|
||||
for j = 1, 160 do
|
||||
local nodename = env:get_node({x=x,y=y+j,z=z}).name
|
||||
if nodename ~= "air" and nodename ~= "ignore"
|
||||
and nodename ~= "default:leaves" and nodename ~= "default:jungleleaves"
|
||||
and nodename ~= "snow:ice" and nodename ~= "snow:needles" then
|
||||
return
|
||||
end
|
||||
end
|
||||
-- Excavate path.
|
||||
for j = 1, 160 do
|
||||
local nodename = env:get_node({x=x,y=y+j,z=z}).name
|
||||
if nodename ~= "air" and nodename ~= "ignore" then
|
||||
env:remove_node({x=x,y=y+j,z=z})
|
||||
end
|
||||
end
|
||||
-- Add meseorite.
|
||||
env:add_node({x=x,y=y-conrad-1,z=z},{name="default:mese"})
|
||||
-- Excavate cone and count excavated nodes.
|
||||
local exsto = 0
|
||||
local exdsto = 0
|
||||
local exdirt = 0
|
||||
local exdsan = 0
|
||||
local exsan = 0
|
||||
local extree = 0
|
||||
local exjtree = 0
|
||||
for j = 0, conrad * 2 do
|
||||
for i = -j, j do
|
||||
for k = -j, j do
|
||||
if i ^ 2 + k ^ 2 <= j ^ 2 then
|
||||
local exsno = false
|
||||
local nodename = env:get_node({x=x+i,y=y-conrad+j,z=z+k}).name
|
||||
if nodename == "default:stone" then
|
||||
exsto = exsto + 1
|
||||
elseif nodename == "default:desert_stone" then
|
||||
exdsto = exdsto + 1
|
||||
elseif nodename == "default:dirt" or nodename == "default:dirt_with_grass" then
|
||||
exdirt = exdirt + 1
|
||||
elseif nodename == "default:desert_sand" then
|
||||
exdsan = exdsan + 1
|
||||
elseif nodename == "default:sand" then
|
||||
exsan = exsan + 1
|
||||
elseif nodename == "default:tree" then
|
||||
extree = extree + 1
|
||||
elseif nodename == "default:jungletree" then
|
||||
exjtree = exjtree + 1
|
||||
elseif nodename == "snow:snow" then
|
||||
exsno = true
|
||||
end
|
||||
if nodename ~= "air" then
|
||||
env:remove_node({x=x+i,y=y-conrad+j,z=z+k})
|
||||
end
|
||||
if exsno then
|
||||
env:remove_node({x=x+i,y=y-conrad+j,z=z+k})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Calculate proportions of ejecta.
|
||||
local extot = exsto + exdsto + exdirt + exdsan + exsan + extree + exjtree
|
||||
local pexsto = exsto / extot
|
||||
local pexdsto = exdsto / extot
|
||||
local pexdirt = exdirt / extot
|
||||
local pexdsan = exdsan / extot
|
||||
local pexsan = exsan / extot
|
||||
local pextree = extree / extot
|
||||
local pexjtree = exjtree / extot
|
||||
-- Print to terminal.
|
||||
if DEBUG then
|
||||
print ("[meseor] Cone radius "..conrad.." node ("..x.." "..y.." "..z..")")
|
||||
print ("[meseor] exsto "..exsto.." exdsto "..exdsto.." exdirt "..exdirt.." exdsan "..exdsan)
|
||||
print ("[meseor] exsan "..exsan.." extree "..extree.." exjtree "..exjtree)
|
||||
print ("[meseor] extot "..extot)
|
||||
end
|
||||
-- Add ejecta.
|
||||
local addtot = 0
|
||||
for rep = 1, 128 do
|
||||
for i = -rimrad, rimrad do
|
||||
for k = -rimrad, rimrad do
|
||||
local rad = (i ^ 2 + k ^ 2) ^ 0.5
|
||||
if rad <= rimrad and math.random() > math.abs(rad - conrad * 1.2) / (conrad * 1.2)
|
||||
and addtot < extot and math.random(3) == 2 then
|
||||
-- Find ground.
|
||||
local groundy = false
|
||||
for j = conrad - 1, -160, -1 do
|
||||
local nodename = env:get_node({x=x+i,y=y+j,z=z+k}).name
|
||||
if nodename == "default:leaves" or nodename == "default:jungleleaves"
|
||||
or nodename == "default:papyrus" or nodename == "default:dry_shrub"
|
||||
or nodename == "default:grass_1" or nodename == "default:grass_2"
|
||||
or nodename == "default:grass_3" or nodename == "default:grass_4"
|
||||
or nodename == "default:grass_5" or nodename == "default:apple"
|
||||
or nodename == "default:junglegrass" or nodename == "snow:needles" then
|
||||
env:remove_node({x=x+i,y=y+j,z=z+k})
|
||||
elseif nodename ~= "air" and nodename ~= "ignore" and nodename ~= "snow:snow"
|
||||
and nodename ~= "default:water_source" and nodename ~= "default:water_flowing" then
|
||||
groundy = y+j
|
||||
break
|
||||
end
|
||||
end
|
||||
if groundy then
|
||||
local x = x + i
|
||||
local y = groundy + 1
|
||||
local z = z + k
|
||||
if math.random() < pexjtree then
|
||||
env:add_node({x=x,y=y,z=z},{name="default:jungletree"})
|
||||
elseif math.random() < pextree then
|
||||
env:add_node({x=x,y=y,z=z},{name="default:tree"})
|
||||
elseif math.random() < pexsan then
|
||||
env:add_node({x=x,y=y,z=z},{name="default:sand"})
|
||||
elseif math.random() < pexdsan then
|
||||
env:add_node({x=x,y=y,z=z},{name="default:desert_sand"})
|
||||
elseif math.random() < pexdirt then
|
||||
env:add_node({x=x,y=y,z=z},{name="default:dirt"})
|
||||
elseif math.random() < pexdsto then
|
||||
env:add_node({x=x,y=y,z=z},{name="default:desert_stone"})
|
||||
elseif math.random() < pexsto then
|
||||
if math.random(STOCHA) == 2 then
|
||||
env:add_node({x=x,y=y,z=z},{name="default:stone"})
|
||||
else
|
||||
env:add_node({x=x,y=y,z=z},{name="default:gravel"})
|
||||
end
|
||||
end
|
||||
addtot = addtot + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if addtot == extot then break end
|
||||
end
|
||||
-- Play sound.
|
||||
minetest.sound_play("meseor", {gain = 1})
|
||||
-- Damage player if inside rimrad.
|
||||
if DAMAGE then
|
||||
for _,player in ipairs(minetest.get_connected_players()) do
|
||||
local plapos = player:getpos()
|
||||
local pladis = ((plapos.x - x) ^ 2 + (plapos.y - y) ^ 2 + (plapos.z - z) ^ 2) ^ 0.5
|
||||
local pladam = math.ceil((1 - pladis / rimrad) * DAMMAX)
|
||||
if pladam > 0 then
|
||||
player:set_hp(player:get_hp() - pladam)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue