add fire mod and improve human town generation a bit
parent
0326016487
commit
21d79bb6e6
|
@ -0,0 +1,36 @@
|
|||
Minetest Game mod: fire
|
||||
=======================
|
||||
|
||||
License of source code:
|
||||
-----------------------
|
||||
Copyright (C) 2012 Perttu Ahola (celeron55) <celeron55@gmail.com>
|
||||
|
||||
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.
|
||||
|
||||
http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
|
||||
License of media (textures and sounds)
|
||||
--------------------------------------
|
||||
Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
|
||||
http://creativecommons.org/licenses/by-sa/3.0/
|
||||
|
||||
Authors of media files
|
||||
-----------------------
|
||||
Everything not listed in here:
|
||||
Copyright (C) 2012 Perttu Ahola (celeron55) <celeron55@gmail.com>
|
||||
|
||||
fire_small.ogg sampled from:
|
||||
http://www.freesound.org/people/dobroide/sounds/4211/
|
||||
|
||||
fire_large.ogg sampled from:
|
||||
http://www.freesound.org/people/Dynamicell/sounds/17548/
|
||||
|
||||
fire_basic_flame_animated.png:
|
||||
Muadtralk
|
||||
|
||||
fire_flint_steel.png
|
||||
Gambit (WTFPL)
|
||||
|
|
@ -0,0 +1 @@
|
|||
default
|
|
@ -0,0 +1,340 @@
|
|||
-- minetest/fire/init.lua
|
||||
|
||||
-- Global namespace for functions
|
||||
|
||||
fire = {}
|
||||
|
||||
|
||||
-- Register flame nodes
|
||||
|
||||
minetest.register_node("fire:basic_flame", {
|
||||
drawtype = "firelike",
|
||||
tiles = {
|
||||
{
|
||||
name = "fire_basic_flame_animated.png",
|
||||
animation = {
|
||||
type = "vertical_frames",
|
||||
aspect_w = 16,
|
||||
aspect_h = 16,
|
||||
length = 1
|
||||
},
|
||||
},
|
||||
},
|
||||
inventory_image = "fire_basic_flame.png",
|
||||
paramtype = "light",
|
||||
light_source = 14,
|
||||
walkable = false,
|
||||
buildable_to = true,
|
||||
sunlight_propagates = true,
|
||||
damage_per_second = 4,
|
||||
groups = {igniter = 2, dig_immediate = 3, not_in_creative_inventory = 1},
|
||||
on_timer = function(pos)
|
||||
local f = minetest.find_node_near(pos, 1, {"group:flammable"})
|
||||
if not f then
|
||||
minetest.remove_node(pos)
|
||||
return
|
||||
end
|
||||
-- restart timer
|
||||
return true
|
||||
end,
|
||||
drop = "",
|
||||
|
||||
on_construct = function(pos)
|
||||
minetest.get_node_timer(pos):start(math.random(30, 60))
|
||||
minetest.after(0, fire.update_sounds_around, pos)
|
||||
end,
|
||||
|
||||
on_destruct = function(pos)
|
||||
minetest.after(0, fire.update_sounds_around, pos)
|
||||
end,
|
||||
|
||||
on_blast = function()
|
||||
end, -- unaffected by explosions
|
||||
})
|
||||
|
||||
minetest.register_node("fire:permanent_flame", {
|
||||
description = "Permanent Flame",
|
||||
drawtype = "firelike",
|
||||
tiles = {
|
||||
{
|
||||
name = "fire_basic_flame_animated.png",
|
||||
animation = {
|
||||
type = "vertical_frames",
|
||||
aspect_w = 16,
|
||||
aspect_h = 16,
|
||||
length = 1
|
||||
},
|
||||
},
|
||||
},
|
||||
inventory_image = "fire_basic_flame.png",
|
||||
paramtype = "light",
|
||||
light_source = 14,
|
||||
walkable = false,
|
||||
buildable_to = true,
|
||||
sunlight_propagates = true,
|
||||
damage_per_second = 4,
|
||||
groups = {igniter = 2, dig_immediate = 3},
|
||||
drop = "",
|
||||
|
||||
on_blast = function()
|
||||
end,
|
||||
})
|
||||
|
||||
|
||||
-- Flint and steel
|
||||
|
||||
minetest.register_tool("fire:flint_and_steel", {
|
||||
description = "Flint and Steel",
|
||||
inventory_image = "fire_flint_steel.png",
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
itemstack:add_wear(1000)
|
||||
local pt = pointed_thing
|
||||
if pt.type == "node" then
|
||||
local node_under = minetest.get_node(pt.under).name
|
||||
local is_coalblock = node_under == "default:coalblock"
|
||||
local is_tnt = node_under == "tnt:tnt"
|
||||
local is_gunpowder = node_under == "tnt:gunpowder"
|
||||
if minetest.get_item_group(node_under, "flammable") >= 1 or
|
||||
is_coalblock or is_tnt or is_gunpowder then
|
||||
local flame_pos = pt.above
|
||||
if is_coalblock then
|
||||
flame_pos = {x = pt.under.x, y = pt.under.y + 1, z = pt.under.z}
|
||||
elseif is_tnt or is_gunpowder then
|
||||
flame_pos = pt.under
|
||||
end
|
||||
if minetest.get_node(flame_pos).name == "air" or
|
||||
is_tnt or is_gunpowder then
|
||||
local player_name = user:get_player_name()
|
||||
if not minetest.is_protected(flame_pos, player_name) then
|
||||
if is_coalblock then
|
||||
minetest.set_node(flame_pos,
|
||||
{name = "fire:permanent_flame"})
|
||||
elseif is_tnt then
|
||||
minetest.set_node(flame_pos,
|
||||
{name = "tnt:tnt_burning"})
|
||||
elseif is_gunpowder then
|
||||
minetest.set_node(flame_pos,
|
||||
{name = "tnt:gunpowder_burning"})
|
||||
else
|
||||
minetest.set_node(flame_pos,
|
||||
{name = "fire:basic_flame"})
|
||||
end
|
||||
else
|
||||
minetest.chat_send_player(player_name, "This area is protected")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if not minetest.setting_getbool("creative_mode") then
|
||||
return itemstack
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "fire:flint_and_steel",
|
||||
recipe = {
|
||||
{"default:flint", "default:steel_ingot"}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
-- Override coalblock to enable permanent flame above
|
||||
-- Coalblock is non-flammable to avoid unwanted basic_flame nodes
|
||||
|
||||
minetest.override_item("default:coalblock", {
|
||||
after_destruct = function(pos, oldnode)
|
||||
pos.y = pos.y + 1
|
||||
if minetest.get_node(pos).name == "fire:permanent_flame" then
|
||||
minetest.remove_node(pos)
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
|
||||
-- Get sound area of position
|
||||
|
||||
fire.D = 6 -- size of sound areas
|
||||
|
||||
function fire.get_area_p0p1(pos)
|
||||
local p0 = {
|
||||
x = math.floor(pos.x / fire.D) * fire.D,
|
||||
y = math.floor(pos.y / fire.D) * fire.D,
|
||||
z = math.floor(pos.z / fire.D) * fire.D,
|
||||
}
|
||||
local p1 = {
|
||||
x = p0.x + fire.D - 1,
|
||||
y = p0.y + fire.D - 1,
|
||||
z = p0.z + fire.D - 1
|
||||
}
|
||||
return p0, p1
|
||||
end
|
||||
|
||||
|
||||
-- Fire sounds table
|
||||
-- key: position hash of low corner of area
|
||||
-- value: {handle=sound handle, name=sound name}
|
||||
fire.sounds = {}
|
||||
|
||||
|
||||
-- Update fire sounds in sound area of position
|
||||
|
||||
function fire.update_sounds_around(pos)
|
||||
local p0, p1 = fire.get_area_p0p1(pos)
|
||||
local cp = {x = (p0.x + p1.x) / 2, y = (p0.y + p1.y) / 2, z = (p0.z + p1.z) / 2}
|
||||
local flames_p = minetest.find_nodes_in_area(p0, p1, {"fire:basic_flame"})
|
||||
--print("number of flames at "..minetest.pos_to_string(p0).."/"
|
||||
-- ..minetest.pos_to_string(p1)..": "..#flames_p)
|
||||
local should_have_sound = (#flames_p > 0)
|
||||
local wanted_sound = nil
|
||||
if #flames_p >= 9 then
|
||||
wanted_sound = {name = "fire_large", gain = 0.7}
|
||||
elseif #flames_p > 0 then
|
||||
wanted_sound = {name = "fire_small", gain = 0.9}
|
||||
end
|
||||
local p0_hash = minetest.hash_node_position(p0)
|
||||
local sound = fire.sounds[p0_hash]
|
||||
if not sound then
|
||||
if should_have_sound then
|
||||
fire.sounds[p0_hash] = {
|
||||
handle = minetest.sound_play(wanted_sound,
|
||||
{pos = cp, max_hear_distance = 16, loop = true}),
|
||||
name = wanted_sound.name,
|
||||
}
|
||||
end
|
||||
else
|
||||
if not wanted_sound then
|
||||
minetest.sound_stop(sound.handle)
|
||||
fire.sounds[p0_hash] = nil
|
||||
elseif sound.name ~= wanted_sound.name then
|
||||
minetest.sound_stop(sound.handle)
|
||||
fire.sounds[p0_hash] = {
|
||||
handle = minetest.sound_play(wanted_sound,
|
||||
{pos = cp, max_hear_distance = 16, loop = true}),
|
||||
name = wanted_sound.name,
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Extinguish all flames quickly with water, snow, ice
|
||||
|
||||
minetest.register_abm({
|
||||
label = "Extinguish flame",
|
||||
nodenames = {"fire:basic_flame", "fire:permanent_flame"},
|
||||
neighbors = {"group:puts_out_fire"},
|
||||
interval = 3,
|
||||
chance = 1,
|
||||
catch_up = false,
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
minetest.remove_node(pos)
|
||||
minetest.sound_play("fire_extinguish_flame",
|
||||
{pos = pos, max_hear_distance = 16, gain = 0.25})
|
||||
end,
|
||||
})
|
||||
|
||||
|
||||
-- Enable the following ABMs according to 'enable fire' setting
|
||||
|
||||
local fire_enabled = minetest.setting_getbool("enable_fire")
|
||||
if fire_enabled == nil then
|
||||
-- New setting not specified, check for old setting.
|
||||
-- If old setting is also not specified, 'not nil' is true.
|
||||
fire_enabled = not minetest.setting_getbool("disable_fire")
|
||||
end
|
||||
|
||||
if not fire_enabled then
|
||||
|
||||
-- Remove basic flames only
|
||||
|
||||
minetest.register_abm({
|
||||
label = "Remove disabled fire",
|
||||
nodenames = {"fire:basic_flame"},
|
||||
interval = 7,
|
||||
chance = 1,
|
||||
catch_up = false,
|
||||
action = minetest.remove_node,
|
||||
})
|
||||
|
||||
else -- Fire enabled
|
||||
|
||||
-- Ignite neighboring nodes, add basic flames
|
||||
|
||||
minetest.register_abm({
|
||||
label = "Ignite flame",
|
||||
nodenames = {"group:flammable"},
|
||||
neighbors = {"group:igniter"},
|
||||
interval = 7,
|
||||
chance = 12,
|
||||
catch_up = false,
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
-- If there is water or stuff like that around node, don't ignite
|
||||
if minetest.find_node_near(pos, 1, {"group:puts_out_fire"}) then
|
||||
return
|
||||
end
|
||||
local p = minetest.find_node_near(pos, 1, {"air"})
|
||||
if p then
|
||||
minetest.set_node(p, {name = "fire:basic_flame"})
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
-- Remove flammable nodes
|
||||
|
||||
minetest.register_abm({
|
||||
label = "Remove flammable nodes",
|
||||
nodenames = {"fire:basic_flame"},
|
||||
neighbors = "group:flammable",
|
||||
interval = 5,
|
||||
chance = 18,
|
||||
catch_up = false,
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
local p = minetest.find_node_near(pos, 1, {"group:flammable"})
|
||||
if p then
|
||||
-- remove flammable nodes around flame
|
||||
local flammable_node = minetest.get_node(p)
|
||||
local def = minetest.registered_nodes[flammable_node.name]
|
||||
if def.on_burn then
|
||||
def.on_burn(p)
|
||||
else
|
||||
minetest.remove_node(p)
|
||||
nodeupdate(p)
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
end
|
||||
|
||||
|
||||
-- Rarely ignite things from far
|
||||
|
||||
--[[ Currently disabled to reduce the chance of uncontrollable spreading
|
||||
fires that disrupt servers. Also for less lua processing load.
|
||||
|
||||
minetest.register_abm({
|
||||
nodenames = {"group:igniter"},
|
||||
neighbors = {"air"},
|
||||
interval = 5,
|
||||
chance = 10,
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
local reg = minetest.registered_nodes[node.name]
|
||||
if not reg or not reg.groups.igniter or reg.groups.igniter < 2 then
|
||||
return
|
||||
end
|
||||
local d = reg.groups.igniter
|
||||
local p = minetest.find_node_near(pos, d, {"group:flammable"})
|
||||
if p then
|
||||
-- If there is water or stuff like that around flame, don't ignite
|
||||
if fire.flame_should_extinguish(p) then
|
||||
return
|
||||
end
|
||||
local p2 = fire.find_pos_for_flame_around(p)
|
||||
if p2 then
|
||||
minetest.set_node(p2, {name = "fire:basic_flame"})
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
--]]
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 646 B |
Binary file not shown.
After Width: | Height: | Size: 1.0 KiB |
Binary file not shown.
After Width: | Height: | Size: 3.0 KiB |
|
@ -3,6 +3,8 @@
|
|||
-- are accessed.
|
||||
Parameters = { }
|
||||
|
||||
--- When true, characters teleport to destinations immediately
|
||||
Parameters.fast = true
|
||||
--- Half size of the astral plane
|
||||
Parameters.astral_plane_half_size = 10
|
||||
--- Number of deities to create
|
||||
|
@ -13,6 +15,8 @@ Parameters.municipality_half_size = 15
|
|||
Parameters.minimum_municipality_distance = 100
|
||||
--- Minimum number of mortals spawned by a creator deity
|
||||
Parameters.minimum_eden_mortals = 5
|
||||
--- Max attempts allowed when randomly choosing a spot for a child site
|
||||
Parameters.site_request_space_randomly_max_attempts = 20
|
||||
--- Extra number of mortals that may be spawned by a creator deity
|
||||
Parameters.extra_eden_mortals = 5
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -62,6 +62,15 @@ function Site:get_next_order()
|
|||
local order = BuildOrder.get(id)
|
||||
if order and not order:is_complete() then return order end
|
||||
end
|
||||
|
||||
-- nothing found, check our children
|
||||
for k,id in pairs(self.children) do
|
||||
local child = Site.get(id)
|
||||
if child then
|
||||
local order = child:get_next_order()
|
||||
if order then return order end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Request space in this site for the given child site
|
||||
|
@ -72,38 +81,53 @@ end
|
|||
-- @param size a vector specifying the space needed
|
||||
-- @return true when space was found
|
||||
function Site:request_space(child, size)
|
||||
for x = self.min.x,(self.max.x-size.x) do
|
||||
for z = self.min.z,(self.max.z-size.z) do
|
||||
if self:allocate_space(child, size, x, z) then return true end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Like `request_space`, but positions are chosen randomly rather than scanned.
|
||||
function Site:request_space_randomly(child, size)
|
||||
local attempts = 0
|
||||
while attempts < Parameters.site_request_space_randomly_max_attempts do
|
||||
local x = math.random(self.min.x,(self.max.x-size.x))
|
||||
local z = math.random(self.min.z,(self.max.z-size.z))
|
||||
if self:allocate_space(child, size, x, z) then return true end
|
||||
attempts = attempts + 1
|
||||
end
|
||||
end
|
||||
|
||||
function Site:allocate_space(child, size, x, z)
|
||||
local ok, other
|
||||
local min = vector.new(0,self.pos.y,0)
|
||||
local max = vector.new(0,self.pos.y + size.y - 1,0)
|
||||
local ok, other
|
||||
for x = self.min.x,(self.max.x-size.x+1) do
|
||||
for z = self.min.z,(self.max.z-size.z+1) do
|
||||
min.x = x
|
||||
min.z = z
|
||||
max.x = x + size.x - 1
|
||||
max.z = z + size.z - 1
|
||||
min.x = x
|
||||
min.z = z
|
||||
max.x = x + size.x
|
||||
max.z = z + size.z
|
||||
|
||||
ok = true
|
||||
for k, id in pairs(self.children) do
|
||||
other = Site.get(id)
|
||||
if stm.rectangles_overlap(min,max,other.min,other.max) then
|
||||
ok = false
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if ok then
|
||||
child.pos = vector.new(
|
||||
math.floor(min.x + (max.x - min.x)/2),
|
||||
math.floor(min.y),
|
||||
math.floor(min.z + (max.z - min.z)/2)
|
||||
)
|
||||
child.min = min
|
||||
child.max = max
|
||||
table.insert(self.children, child.id)
|
||||
return true
|
||||
end
|
||||
ok = true
|
||||
for k, id in pairs(self.children) do
|
||||
other = Site.get(id)
|
||||
if stm.rectangles_overlap(min,max,other.min,other.max) then
|
||||
ok = false
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if ok then
|
||||
child.pos = vector.new(
|
||||
math.floor(min.x + (max.x - min.x)/2),
|
||||
math.floor(min.y),
|
||||
math.floor(min.z + (max.z - min.z)/2)
|
||||
)
|
||||
child.min = min
|
||||
child.max = max
|
||||
table.insert(self.children, child.id)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function Site:get_def()
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
local function create_initial_build_orders(self)
|
||||
local order = BuildOrder.from_schematic(self.pos, 'fountain')
|
||||
BuildOrder.register(order)
|
||||
self:add_order(order)
|
||||
end
|
||||
|
||||
return {
|
||||
create_initial_build_orders = create_initial_build_orders
|
||||
}
|
|
@ -6,7 +6,7 @@ local function find_suitable_location(self, hint)
|
|||
local max = vector.new(pos.x + size, pos.y, pos.z + size)
|
||||
local variance, y_min, y_max = MapData.get_surface_variance(min, max)
|
||||
|
||||
if variance > max_variance then return nil end
|
||||
-- if variance > max_variance then return nil end
|
||||
|
||||
self.pos = vector.new(pos.x, y_min, pos.z)
|
||||
self.min = vector.new(pos.x - size, y_min, pos.z - size)
|
||||
|
@ -18,6 +18,22 @@ local function create_initial_build_orders(self)
|
|||
local order = BuildOrder.from_generator(self.min, self.max, 'flatland')
|
||||
BuildOrder.register(order)
|
||||
self:add_order(order)
|
||||
|
||||
local fountain = Site.new()
|
||||
fountain.type = 'fountain'
|
||||
local found_space = self:request_space_randomly(fountain, stm.schematic_size('fountain'))
|
||||
if found_space then
|
||||
fountain:create_initial_build_orders()
|
||||
Site.register(fountain)
|
||||
end
|
||||
|
||||
local temple = Site.new()
|
||||
temple.type = 'temple_human'
|
||||
local found_space = self:request_space_randomly(temple, stm.schematic_size('temple_human'))
|
||||
if found_space then
|
||||
temple:create_initial_build_orders()
|
||||
Site.register(temple)
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
local function pick_style(self)
|
||||
local schematics = {'house1', 'house2', 'house3'}
|
||||
local schematics = {'house_human1', 'house_human2', 'house_human3'}
|
||||
self.style = stm.pick_one(schematics)
|
||||
return stm.schematic_size(self.style)
|
||||
end
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
local function create_initial_build_orders(self)
|
||||
local order = BuildOrder.from_schematic(self.pos, 'temple_human')
|
||||
BuildOrder.register(order)
|
||||
self:add_order(order)
|
||||
end
|
||||
|
||||
return {
|
||||
create_initial_build_orders = create_initial_build_orders
|
||||
}
|
|
@ -9,6 +9,12 @@ return {
|
|||
char.path_wait = 0
|
||||
end,
|
||||
perform = function(char, state)
|
||||
-- teleport when in fast mode
|
||||
if Parameters.fast then
|
||||
char.position = state.dest
|
||||
return true
|
||||
end
|
||||
|
||||
if state.state == PATH then
|
||||
-- couldn't path due to timeout, try again later
|
||||
if stm.data.time < char.path_wait then return end
|
||||
|
|
|
@ -218,7 +218,7 @@ end
|
|||
|
||||
--- Return the first element (v) of `t` for which `f(v, k)` returns true
|
||||
function stm.find_one(t, f)
|
||||
for _,v in pairs(t) do
|
||||
for k,v in pairs(t) do
|
||||
if f(v, k) then return v end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue