minetest-mods/crops/init.lua

386 lines
10 KiB
Lua

--[[
Copyright (C) 2015 - Auke Kok <sofar@foo-projects.org>
"crops" 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.
--]]
crops = {}
crops.plants = {}
crops.settings = {}
local settings = {}
settings.easy = {
chance = 4,
interval = 30,
light = 8,
watercan = 25,
watercan_max = 90,
watercan_uses = 20,
damage_chance = 8,
damage_interval = 30,
damage_tick_min = 0,
damage_tick_max = 1,
damage_max = 25,
hydration = false,
}
settings.normal = {
chance = 8,
interval = 30,
light = 10,
watercan = 25,
watercan_max = 90,
watercan_uses = 20,
damage_chance = 8,
damage_interval = 30,
damage_tick_min = 0,
damage_tick_max = 5,
damage_max = 50,
hydration = true,
}
settings.difficult = {
chance = 16,
interval = 30,
light = 13,
watercan = 25,
watercan_max = 100,
watercan_uses = 20,
damage_chance = 4,
damage_interval = 30,
damage_tick_min = 3,
damage_tick_max = 7,
damage_max = 100,
hydration = true,
}
local worldpath = minetest.get_worldpath()
local modpath = minetest.get_modpath(minetest.get_current_modname())
-- Load support for intllib.
local S, _ = dofile(modpath .. "/intllib.lua")
crops.intllib = S
dofile(modpath .. "/crops_settings.txt")
if io.open(worldpath .. "/crops_settings.txt", "r") == nil then
io.input(modpath .. "/crops_settings.txt")
io.output(worldpath .. "/crops_settings.txt")
local size = 4096
while true do
local buf = io.read(size)
if not buf then
io.close()
break
end
io.write(buf)
end
else
dofile(worldpath .. "/crops_settings.txt")
end
if not crops.difficulty then
crops.difficulty = "normal"
minetest.log("error", "[crops] "..S("Defaulting to \"normal\" difficulty settings"))
end
crops.settings = settings[crops.difficulty]
if not crops.settings then
minetest.log("error", "[crops] "..S("Defaulting to \"normal\" difficulty settings"))
crops.settings = settings.normal
end
if crops.settings.hydration then
minetest.log("action", "[crops] "..S("Hydration and dehydration mechanics are enabled."))
end
local find_plant = function(node)
for i = 1,table.getn(crops.plants) do
if crops.plants[i].name == node.name then
return crops.plants[i]
end
end
minetest.log("error", "[crops] "..S("Unable to find plant \"@1\" in crops table", node.name))
return nil
end
crops.register = function(plantdef)
table.insert(crops.plants, plantdef)
end
crops.plant = function(pos, node)
minetest.set_node(pos, node)
local meta = minetest.get_meta(pos)
local plant = find_plant(node)
meta:set_int("crops_water", math.max(plant.properties.waterstart, 1))
meta:set_int("crops_damage", 0)
end
crops.can_grow = function(pos)
if minetest.get_node_light(pos) < crops.settings.light then
return false
end
local node = minetest.get_node(pos)
local plant = find_plant(node)
if not plant then
return false
end
local meta = minetest.get_meta(pos)
if crops.settings.hydration then
local water = meta:get_int("crops_water")
if water < plant.properties.wither or water > plant.properties.soak then
if math.random(0,1) == 0 then
return false
end
end
-- growing costs water!
meta:set_int("crops_water", math.max(1, water - 10))
end
-- damaged plants are less likely to grow
local damage = meta:get_int("crops_damage")
if not damage == 0 then
if math.random(math.min(50, damage), 100) > 75 then
return false
end
end
-- allow the plant to grow
return true
end
crops.particles = function(pos, flag)
if flag == 0 then
-- wither (0)
minetest.add_particlespawner({
amount = 1 * crops.settings.interval,
time = crops.settings.interval,
minpos = { x = pos.x - 0.4, y = pos.y - 0.4, z = pos.z - 0.4 },
maxpos = { x = pos.x + 0.4, y = pos.y + 0.4, z = pos.z + 0.4 },
minvel = { x = 0, y = 0.2, z = 0 },
maxvel = { x = 0, y = 0.4, z = 0 },
minacc = { x = 0, y = 0, z = 0 },
maxacc = { x = 0, y = 0.2, z = 0 },
minexptime = 3,
maxexptime = 5,
minsize = 1,
maxsize = 2,
collisiondetection = false,
texture = "crops_wither.png",
vertical = true,
})
elseif flag == 1 then
-- soak (1)
minetest.add_particlespawner({
amount = 8 * crops.settings.interval,
time = crops.settings.interval,
minpos = { x = pos.x - 0.4, y = pos.y - 0.4, z = pos.z - 0.4 },
maxpos = { x = pos.x + 0.4, y = pos.y - 0.4, z = pos.z + 0.4 },
minvel = { x = -0.04, y = 0, z = -0.04 },
maxvel = { x = 0.04, y = 0, z = 0.04 },
minacc = { x = 0, y = 0, z = 0 },
maxacc = { x = 0, y = 0, z = 0 },
minexptime = 3,
maxexptime = 5,
minsize = 1,
maxsize = 2,
collisiondetection = false,
texture = "crops_soak.png",
vertical = false,
})
elseif flag == 2 then
-- watering (2)
minetest.add_particlespawner({
amount = 30,
time = 3,
minpos = { x = pos.x - 0.4, y = pos.y - 0.4, z = pos.z - 0.4 },
maxpos = { x = pos.x + 0.4, y = pos.y + 0.4, z = pos.z + 0.4 },
minvel = { x = 0, y = 0.0, z = 0 },
maxvel = { x = 0, y = 0.0, z = 0 },
minacc = { x = 0, y = -9.81, z = 0 },
maxacc = { x = 0, y = -9.81, z = 0 },
minexptime = 2,
maxexptime = 2,
minsize = 1,
maxsize = 3,
collisiondetection = false,
texture = "crops_watering.png",
vertical = true,
})
else
-- withered/rotting (3)
minetest.add_particlespawner({
amount = 20,
time = 30,
minpos = { x = pos.x + 0.3, y = pos.y - 0.5, z = pos.z - 0.5 },
maxpos = { x = pos.x + 0.5, y = pos.y + 0.5, z = pos.z + 0.5 },
minvel = { x = -0.6, y = -0.1, z = -0.2 },
maxvel = { x = -0.4, y = 0.1, z = 0.2 },
minacc = { x = 0.4, y = 0, z = -0.1 },
maxacc = { x = 0.5, y = 0, z = 0.1 },
minexptime = 2,
maxexptime = 4,
minsize = 1,
maxsize = 1,
collisiondetection = false,
texture = "crops_flies.png",
vertical = true,
})
minetest.add_particlespawner({
amount = 20,
time = 30,
minpos = { x = pos.x - 0.3, y = pos.y - 0.5, z = pos.z - 0.5 },
maxpos = { x = pos.x - 0.5, y = pos.y + 0.5, z = pos.z + 0.5 },
minvel = { x = 0.6, y = -0.1, z = -0.2 },
maxvel = { x = 0.4, y = 0.1, z = 0.2 },
minacc = { x = -0.4, y = 0, z = -0.1 },
maxacc = { x = -0.5, y = 0, z = 0.1 },
minexptime = 2,
maxexptime = 4,
minsize = 1,
maxsize = 1,
collisiondetection = false,
texture = "crops_flies.png",
vertical = true,
})
minetest.add_particlespawner({
amount = 20,
time = 30,
minpos = { x = pos.x - 0.5, y = pos.y - 0.5, z = pos.z + 0.3 },
maxpos = { x = pos.x + 0.5, y = pos.y + 0.5, z = pos.z + 0.5 },
minvel = { z = -0.6, y = -0.1, x = -0.2 },
maxvel = { z = -0.4, y = 0.1, x = 0.2 },
minacc = { z = 0.4, y = 0, x = -0.1 },
maxacc = { z = 0.5, y = 0, x = 0.1 },
minexptime = 2,
maxexptime = 4,
minsize = 1,
maxsize = 1,
collisiondetection = false,
texture = "crops_flies.png",
vertical = true,
})
minetest.add_particlespawner({
amount = 20,
time = 30,
minpos = { x = pos.x - 0.5, y = pos.y - 0.5, z = pos.z - 0.3 },
maxpos = { x = pos.x + 0.5, y = pos.y + 0.5, z = pos.z - 0.5 },
minvel = { z = 0.6, y = -0.1, x = -0.2 },
maxvel = { z = 0.4, y = 0.1, x = 0.2 },
minacc = { z = -0.4, y = 0, x = -0.1 },
maxacc = { z = -0.5, y = 0, x = 0.1 },
minexptime = 2,
maxexptime = 4,
minsize = 1,
maxsize = 1,
collisiondetection = false,
texture = "crops_flies.png",
vertical = true,
})
end
end
crops.die = function(pos)
crops.particles(pos, 3)
local node = minetest.get_node(pos)
local plant = find_plant(node)
plant.properties.die(pos)
minetest.sound_play("crops_flies", {pos=pos, gain=0.8})
end
if crops.settings.hydration then
dofile(modpath .. "/tools.lua")
end
-- crop nodes, crafts, craftitems
dofile(modpath .. "/melon.lua")
dofile(modpath .. "/pumpkin.lua")
dofile(modpath .. "/corn.lua")
dofile(modpath .. "/tomato.lua")
dofile(modpath .. "/potato.lua")
dofile(modpath .. "/polebean.lua")
local nodenames = {}
for i = 1,table.getn(crops.plants) do
table.insert(nodenames, crops.plants[i].name)
end
-- water handling code
if crops.settings.hydration then
minetest.register_abm({
nodenames = nodenames,
interval = crops.settings.damage_interval,
chance = crops.settings.damage_chance,
action = function(pos, node, active_object_count, active_object_count_wider)
local meta = minetest.get_meta(pos)
local water = meta:get_int("crops_water")
local damage = meta:get_int("crops_damage")
-- get plant specific data
local plant = find_plant(node)
if plant == nil then
return
end
-- increase water for nearby water sources
local f = minetest.find_node_near(pos, 1, {"default:water_source", "default:water_flowing"})
if not f == nil then
water = math.min(100, water + 2)
else
f = minetest.find_node_near(pos, 2, {"default:water_source", "default:water_flowing"})
if not f == nil then
water = math.min(100, water + 1)
end
end
if minetest.get_node_light(pos, nil) < plant.properties.night then
-- compensate for light: at night give some water back to the plant
water = math.min(100, water + 1)
else
-- dry out the plant
water = math.max(1, water - plant.properties.wateruse)
end
meta:set_int("crops_water", water)
-- for convenience, copy water attribute to top half
if not plant.properties.doublesize == nil and plant.properties.doublesize then
local above = { x = pos.x, y = pos.y + 1, z = pos.z}
local abovemeta = minetest.get_meta(above)
abovemeta:set_int("crops_water", water)
end
if water <= plant.properties.wither_damage then
crops.particles(pos, 0)
damage = damage + math.random(crops.settings.damage_tick_min, crops.settings.damage_tick_max)
elseif water <= plant.properties.wither then
crops.particles(pos, 0)
return
elseif water >= plant.properties.soak_damage then
crops.particles(pos, 1)
damage = damage + math.random(crops.settings.damage_tick_min, crops.settings.damage_tick_max)
elseif water >= plant.properties.soak then
crops.particles(pos, 1)
return
end
meta:set_int("crops_damage", math.min(crops.settings.damage_max, damage))
-- is it dead?
if damage >= 100 then
crops.die(pos)
end
end
})
end
-- cooking recipes that mix craftitems
dofile(modpath .. "/cooking.lua")
dofile(modpath .. "/mapgen.lua")
minetest.log("action", "[crops] "..S("Loaded!"))