330 lines
11 KiB
Lua
330 lines
11 KiB
Lua
--[[ Terumet v3.0
|
|
|
|
Mod for open-source voxel game Minetest (https://www.minetest.net/)
|
|
Written for Minetest version 5.0.0
|
|
Now also supports Minetest 0.4.17
|
|
|
|
Creates a new ore in the world which can be used to make useful alloys
|
|
and heat-powered machines.
|
|
|
|
By Terumoc [https://github.com/Terumoc]
|
|
and with contributions from:
|
|
> obl3pplifp (https://github.com/obl3pplifp) for bug reports, information, ideas, and other considerable contributions
|
|
> RSL-Redstonier [https://github.com/RSL-Redstonier]
|
|
> Chem871 [https://github.com/Chemguy99] for many ideas and requests
|
|
|
|
BIG Thanks to all contributors for their input!
|
|
|
|
]]--
|
|
|
|
--[[ Copyright (C) 2017-2019 Terumoc (Scott Horvath)
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>. ]]
|
|
|
|
terumet = {}
|
|
terumet.version = {major=3, minor=0, patch=0}
|
|
local ver = terumet.version
|
|
terumet.version_text = ver.major .. '.' .. ver.minor .. '.' .. ver.patch
|
|
terumet.mod_name = ":terumet"
|
|
|
|
-- this isn't the suggested way to check for game version but... it works for my purposes
|
|
terumet.legacy = minetest.get_version().string:find('0.4')
|
|
|
|
if terumet.legacy then
|
|
minetest.log('[terumet] MTv0.4.* detected - in legacy mode!')
|
|
end
|
|
|
|
terumet.RAND = PcgRandom(os.time())
|
|
|
|
local FMT = string.format
|
|
minetest.register_chatcommand( 'item_info', {
|
|
params = '',
|
|
description = 'Get a complete description of the ItemStack in your hand',
|
|
privs = {debug=true},
|
|
func = function(name)
|
|
local player = minetest.get_player_by_name(name)
|
|
if player then
|
|
local witem = player:get_wielded_item()
|
|
if witem:is_empty() then
|
|
return true, "You're not holding anything."
|
|
else
|
|
local def = witem:get_definition()
|
|
local wear = witem:get_wear()
|
|
local wear_pct = FMT('%.1f%%', wear / 65535 * 100.0)
|
|
if def then
|
|
return true, FMT('%s "%s" #%s/%s w:%s (%s)',
|
|
minetest.colorize('#ff0', witem:get_name()),
|
|
def.description,
|
|
witem:get_count(),
|
|
minetest.colorize('#0ff', def.stack_max),
|
|
minetest.colorize('#f0f', wear),
|
|
minetest.colorize('#f0f', wear_pct)
|
|
)
|
|
else
|
|
return true, FMT('*NO DEF* %s #%s w:%s (%s)',
|
|
minetest.colorize('#ff0', witem:get_name()),
|
|
witem:get_count(),
|
|
minetest.colorize('#f0f', wear),
|
|
minetest.colorize('#f0f', wear_pct)
|
|
)
|
|
end
|
|
end
|
|
else
|
|
return false, "You aren't a player somehow, sorry?!"
|
|
end
|
|
end
|
|
})
|
|
|
|
function terumet.chance(pct)
|
|
if pct <= 0 then return false end
|
|
if pct >= 100 then return true end
|
|
return terumet.RAND:next(1,100) <= pct
|
|
end
|
|
|
|
-- function for a node's on_blast callback to be removed with a pct% chance
|
|
function terumet.blast_chance(pct, id)
|
|
return function(pos)
|
|
if terumet.chance(pct) then
|
|
minetest.remove_node(pos)
|
|
return {id}
|
|
else
|
|
return nil
|
|
end
|
|
end
|
|
end
|
|
|
|
-- empty function useful for where a callback is necessary but using nil would cause undesired default behavior
|
|
terumet.NO_FUNCTION = function() end
|
|
terumet.EMPTY = {}
|
|
terumet.ZERO_XYZ = {x=0,y=0,z=0}
|
|
|
|
function terumet.recipe_3x3(i)
|
|
return {
|
|
{i, i, i}, {i, i, i}, {i, i, i}
|
|
}
|
|
end
|
|
|
|
function terumet.recipe_box(outer, inner)
|
|
return {
|
|
{outer, outer, outer}, {outer, inner, outer}, {outer, outer, outer}
|
|
}
|
|
end
|
|
|
|
function terumet.recipe_plus(i)
|
|
return {
|
|
{'', i, ''}, {i, i, i}, {'', i, ''}
|
|
}
|
|
end
|
|
|
|
function terumet.random_velocity(max_tenths)
|
|
return {
|
|
x = terumet.RAND:next(-max_tenths,max_tenths) / 10,
|
|
y = terumet.RAND:next(-max_tenths,max_tenths) / 10,
|
|
z = terumet.RAND:next(-max_tenths,max_tenths) / 10
|
|
}
|
|
end
|
|
|
|
function terumet.particle_stream(pointA, pointB, density, particle_data, player)
|
|
local dist_vector = {x=(pointB.x-pointA.x), y=(pointB.y-pointA.y), z=(pointB.z-pointA.z)}
|
|
local dist = vector.length(dist_vector)
|
|
local pcount = dist * density
|
|
if pcount < 1 then return end -- guard against div/0
|
|
local step = {x=(dist_vector.x/pcount), y=(dist_vector.y/pcount), z=(dist_vector.z/pcount)}
|
|
local ppos = vector.new(pointA)
|
|
for _ = 1,pcount do
|
|
ppos = util3d.pos_plus(ppos, step)
|
|
minetest.add_particle{
|
|
pos = vector.new(ppos),
|
|
velocity=terumet.random_velocity(5),
|
|
expirationtime=(particle_data.expiration or 1),
|
|
size=(particle_data.size or 1),
|
|
glow=(particle_data.glow or 1),
|
|
playername=player,
|
|
texture=particle_data.texture,
|
|
animation=particle_data.animation
|
|
}
|
|
end
|
|
end
|
|
|
|
function terumet.format_time(t)
|
|
return string.format('%.1f s', t or 0)
|
|
end
|
|
|
|
function terumet.do_lua_file(name)
|
|
dofile(minetest.get_modpath("ip_terumet") .. '/' .. name .. '.lua')
|
|
end
|
|
|
|
-- create a copy of node groups from an unlit machine for lit version of machine
|
|
function terumet.create_lit_node_groups(unlit_groups)
|
|
local new_groups = {not_in_creative_inventory=1}
|
|
for k,v in pairs(unlit_groups) do new_groups[k] = v end
|
|
return new_groups
|
|
end
|
|
|
|
function terumet.itemstack_desc(stack)
|
|
local stack_desc = stack:get_definition().description
|
|
-- use only what is before a newline if one is in the description
|
|
if stack_desc:find('\n') then stack_desc = stack_desc:match('(.*)\n') end
|
|
if stack:get_count() > 1 then
|
|
return string.format('%s (x%d)', stack_desc, stack:get_count())
|
|
else
|
|
return stack_desc
|
|
end
|
|
end
|
|
|
|
-- given a table with 'group:XXX' keys and a node/item definition with groups, return the
|
|
-- (first) value in the table where node/item has a group key of XXX, otherwise nil
|
|
function terumet.match_group_key(table, def)
|
|
if not def then return nil end
|
|
for group_name,_ in pairs(def.groups) do
|
|
local grp_key = 'group:'..group_name
|
|
if table[grp_key] then
|
|
return table[grp_key]
|
|
end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
function terumet.id(id, number)
|
|
if number then
|
|
return string.format('%s:%s %d', terumet.mod_name, id, number)
|
|
else
|
|
return string.format('%s:%s', terumet.mod_name, id)
|
|
end
|
|
end
|
|
|
|
function terumet.give_player_item(pos, player, stack)
|
|
local inv = player:get_inventory()
|
|
local leftover = inv:add_item("main", stack)
|
|
if leftover and not leftover:is_empty() then
|
|
minetest.item_drop(leftover, player, player:get_pos())
|
|
end
|
|
end
|
|
|
|
function terumet.tex(id)
|
|
-- accepts both base ids (assuming this mod) and full mod ids
|
|
-- ex: terumet.tex('ingot_raw') -> 'terumet_ingot_raw.png'
|
|
-- terumet.tex('default:cobble') -> 'default_cobble.png'
|
|
|
|
if id:match(':') then
|
|
id = id:sub(2)
|
|
return string.format('%s.png', id:gsub(':', '_'))
|
|
else
|
|
return string.format('%s_%s.png', "terumet", id)
|
|
end
|
|
end
|
|
|
|
function terumet.item_desc(name, xinfo)
|
|
if xinfo then
|
|
return string.format("%s\n%s", name, minetest.colorize(terumet.options.misc.TIP_COLOR, xinfo))
|
|
else
|
|
return name
|
|
end
|
|
end
|
|
|
|
function terumet.crystal_tex(color)
|
|
return string.format('%s^[multiply:%s', terumet.tex('item_cryst'), color)
|
|
end
|
|
|
|
function terumet.tex_comp(base_tex, overlay_id)
|
|
return base_tex .. '^' .. terumet.tex(overlay_id)
|
|
end
|
|
|
|
function terumet.tex_trans(id, rot)
|
|
return terumet.tex(id) .. '^[transform' .. rot
|
|
end
|
|
|
|
local HEAR_DIST = 12
|
|
terumet.squishy_node_sounds = {
|
|
footstep = {name='terumet_squish_step', max_hear_distance=HEAR_DIST},
|
|
dig = {name='terumet_squish_dig', max_hear_distance=HEAR_DIST},
|
|
dug = {name='terumet_squish_dug', max_hear_distance=HEAR_DIST},
|
|
place = {name='terumet_squish_place', max_hear_distance=HEAR_DIST},
|
|
}
|
|
|
|
terumet.do_lua_file('util3d')
|
|
|
|
terumet.do_lua_file('interop/terumet_api')
|
|
terumet.do_lua_file('options')
|
|
terumet.do_lua_file('material/reg_alloy')
|
|
|
|
|
|
-- reg_alloy(name, id, block hardness level, repair material value)
|
|
terumet.reg_alloy('Terucopper', 'tcop', 1, 20)
|
|
terumet.reg_alloy('Terutin', 'ttin', 1, 15)
|
|
terumet.reg_alloy('Terusteel', 'tste', 2, 40)
|
|
terumet.reg_alloy('Terugold', 'tgol', 3, 80)
|
|
terumet.reg_alloy('Coreglass', 'cgls', 4, 120)
|
|
terumet.reg_alloy('Teruchalcum', 'tcha', 2, 60)
|
|
|
|
terumet.do_lua_file('material/ceramic')
|
|
--terumet.do_lua_file('material/thermese')
|
|
terumet.do_lua_file('material/coil')
|
|
--terumet.do_lua_file('material/crushed')
|
|
--terumet.do_lua_file('material/pwood')
|
|
--terumet.do_lua_file('material/tglass')
|
|
terumet.do_lua_file('material/rebar')
|
|
terumet.do_lua_file('material/misc')
|
|
terumet.do_lua_file('material/crystallized')
|
|
--terumet.do_lua_file('material/battery')
|
|
|
|
local id = terumet.id
|
|
|
|
-- register raw terumetal ingot as weak repair-material
|
|
terumet.register_repair_material(id('ingot_raw'), 10)
|
|
|
|
--terumet.do_lua_file('tool/reg_tools')
|
|
|
|
local sword_opts = terumet.options.tools.sword_damage
|
|
|
|
|
|
--terumet.do_lua_file('tool/ore_saw')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- register repairable default tools and materials
|
|
-- {value of 1 item, item id}:
|
|
local dmv_values = {
|
|
steel={10, 'default:steel_ingot'},
|
|
bronze={30, 'default:bronze_ingot'},
|
|
mese={90, 'default:mese_crystal'},
|
|
diamond={100, 'default:diamond'}
|
|
}
|
|
|
|
for dmat, v in pairs(dmv_values) do
|
|
terumet.register_repairable_item("default:pick_"..dmat, v[1]*3)
|
|
terumet.register_repairable_item("default:axe_"..dmat, v[1]*3)
|
|
terumet.register_repairable_item("default:shovel_"..dmat, v[1])
|
|
terumet.register_repairable_item("default:sword_"..dmat, v[1]*2)
|
|
terumet.register_repair_material(v[2], v[1])
|
|
end
|
|
|
|
terumet.do_lua_file('material/concrete')
|
|
terumet.do_lua_file('material/coalproc')
|
|
|
|
--experimental stuff
|
|
--terumet.do_lua_file('material/meson')
|
|
|
|
local INTEROPS = {'3d_armor', 'doors', 'unified_inventory', 'tubelib', 'dungeon_loot', 'moreores', 'farming', 'extra'}
|
|
for _,mod in ipairs(INTEROPS) do
|
|
if minetest.get_modpath(mod) then terumet.do_lua_file('interop/'..mod) end
|
|
end
|
|
|
|
local vacfood_options = terumet.options.vac_oven.VAC_FOOD
|
|
if vacfood_options and vacfood_options.ACTIVE then terumet.do_lua_file('material/vacfood') end
|
|
|
|
terumet.do_lua_file('interop/crusher_misc') |