add fire mod and improve human town generation a bit

master
kaen 2016-08-21 20:42:06 -07:00
parent 0326016487
commit 21d79bb6e6
27 changed files with 479 additions and 31 deletions

36
mods/fire/README.txt Normal file
View File

@ -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)

1
mods/fire/depends.txt Normal file
View File

@ -0,0 +1 @@
default

340
mods/fire/init.lua Normal file
View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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
}

View File

@ -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 {

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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