Noch mehr mods

This commit is contained in:
N-Nachtigal 2025-05-18 04:02:23 +02:00
parent a063db5d3b
commit cf017b2ca1
527 changed files with 21113 additions and 181 deletions

View file

@ -0,0 +1,26 @@
Copyright (c) 2017, Craig Robbins and contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.

View file

@ -0,0 +1,31 @@
# caverealms-lite
Based on the original minetest-caverealms mod (https://github.com/HeroOfTheWinds/minetest-caverealms/).
Adds underground realms to minetest.
This caverealms fork provides all the biomes and decorations from the original caverealms, with several additions and without the overhead of generating caves. This lowers the server resources the mod requires, for example CPU and RAM. This also removes the large lava spills created by the original caverealms.
It is specifically written to work with the mgvalleys mapgen, but will work using other mapgens as well. The mapgen used will determine the shape and size of individual caves. Mapgens that generate only smaller caves may be less suitable for use with this fork than mgvalleys.
Note: For worlds where the original caverealms is already in use, this fork is not advised as a replacement. If used in this way, some unknown nodes and other minor issues should be expected.
## License and Contributors
Source code: FreeBSD License (Simplified)
The original caverealms was licensed as WTFPL.
Contributors:
- Zeno, Shara RedCat - This rewrite
- HeroOfTheWinds, Zeno - Original mod
## Recommended Additions
- VanessaE's HDX texturepacks provide alternative textures. For example,
https://gitlab.com/VanessaE/hdx-128.
- ethereal mod unlocks additional content (https://notabug.org/tenplus1/ethereal).
- mobs_monster mod allows Dungeon Masters to spawn in the Dungeon Master's Lair biome (https://notabug.org/tenplus1/mobs_monster).
- mobs_redo is required to run mobs_monster (https://notabug.org/tenplus1/mobs_redo).
- abritorch adds coloured torches made with caverealms items (https://github.com/Ezhh/abritorch).

View file

@ -0,0 +1,53 @@
local CONFIG_FILE_PREFIX = "caverealms."
caverealms.config = {}
-- This function based on kaeza/minetest-irc/config.lua and used under the
-- terms of BSD 2-clause license.
local function setting(stype, name, default)
local value
if stype == "bool" then
value = minetest.settings:get_bool(CONFIG_FILE_PREFIX..name)
elseif stype == "string" then
value = minetest.settings:get(CONFIG_FILE_PREFIX..name)
elseif stype == "number" then
value = tonumber(minetest.settings:get(CONFIG_FILE_PREFIX..name))
end
if value == nil then
value = default
end
caverealms.config[name] = value
end
--generation settings
setting("number", "ymin", -10000) --bottom realm limit
setting("number", "ymax", -4096) --top realm limit
setting("number", "tcave", 0.75) --cave threshold
--decoration chances
setting("number", "stagcha", 0.03) --chance of stalagmites (was 0.003)
setting("number", "stalcha", 0.03) --chance of stalactites(was 0.003)
setting("number", "h_lag", 8) --max height for stalagmites
setting("number", "h_lac", 8) --...stalactites
setting("number", "crystal", 0.02) --chance of glow crystal formations (was 0.0002)
setting("number", "h_cry", 8) --max height of glow crystals
setting("number", "h_clac", 8) --max height of glow crystal stalactites
setting("number", "gemcha", 0.03) --chance of small glow gems
setting("number", "mushcha", 0.04) --chance of mushrooms
setting("number", "myccha", 0.03) --chance of mycena mushrooms
setting("number", "wormcha", 0.015) --chance of glow worms
setting("number", "giantcha", 0.001) --chance of giant mushrooms
setting("number", "icicha", 0.035) --chance of icicles
setting("number", "flacha", 0.04) --chance of constant flames
--realm limits for Dungeon Masters' Lair
setting("number", "dm_top", -8000) --upper limit
setting("number", "dm_bot", -10000) --lower limit
--should DMs spawn in DM Lair?
setting("bool", "dm_spawn", true)
--Deep cave settings
setting("number", "deep_cave", -7000) -- upper limit

View file

@ -0,0 +1,145 @@
--thin ice to water
minetest.register_craft({
output = "default:water_source",
type = "shapeless",
recipe = {"caverealms:thin_ice"}
})
--use for coal dust
minetest.register_craft({
output = "default:coalblock",
recipe = {
{"caverealms:coal_dust","caverealms:coal_dust","caverealms:coal_dust"},
{"caverealms:coal_dust","caverealms:coal_dust","caverealms:coal_dust"},
{"caverealms:coal_dust","caverealms:coal_dust","caverealms:coal_dust"}
}
})
-- DM statue
minetest.register_craft({
output = "caverealms:dm_statue",
recipe = {
{"caverealms:glow_ore","caverealms:hot_cobble","caverealms:glow_ore"},
{"caverealms:hot_cobble","caverealms:hot_cobble","caverealms:hot_cobble"},
{"caverealms:hot_cobble","caverealms:hot_cobble","caverealms:hot_cobble"}
}
})
-- Glow obsidian brick
minetest.register_craft({
output = "caverealms:glow_obsidian_brick 4",
recipe = {
{"caverealms:glow_obsidian", "caverealms:glow_obsidian"},
{"caverealms:glow_obsidian", "caverealms:glow_obsidian"}
}
})
minetest.register_craft({
output = "caverealms:glow_obsidian_brick_2 4",
recipe = {
{"caverealms:glow_obsidian_2", "caverealms:glow_obsidian_2"},
{"caverealms:glow_obsidian_2", "caverealms:glow_obsidian_2"}
}
})
-- Glow obsidian glass
minetest.register_craft({
output = "caverealms:glow_obsidian_glass 5",
recipe = {
{"default:glass", "default:glass", "default:glass"},
{"default:glass", "default:glass", "caverealms:glow_obsidian"}
}
})
minetest.register_craft({
output = "caverealms:glow_obsidian_glass 5",
recipe = {
{"default:glass", "default:glass", "default:glass"},
{"default:glass", "default:glass", "caverealms:glow_obsidian_2"}
}
})
-- Requires ethereal:fish_raw
if minetest.get_modpath("ethereal") then
-- Professional Fishing Rod
minetest.register_craftitem("caverealms:angler_rod", {
description = "Pro Fishing Rod",
inventory_image = "caverealms_angler_rod.png",
wield_image = "caverealms_angler_rod.png"
})
minetest.register_craft({
output = "caverealms:angler_rod",
recipe = {
{"","","default:steel_ingot"},
{"", "default:steel_ingot", "caverealms:mushroom_gills"},
{"default:steel_ingot", "", "caverealms:mushroom_gills"},
}
})
-- Glow Bait
minetest.register_craftitem("caverealms:glow_bait", {
description = "Glow Bait",
inventory_image = "caverealms_glow_bait.png",
wield_image = "caverealms_glow_bait.png",
})
minetest.register_craft({
output = "caverealms:glow_bait 9",
recipe = {
{"caverealms:glow_worm_green"},
}
})
-- default ethereal fish
local fish = {
{"ethereal:fish_raw"},
}
-- Pro Fishing Rod (Baited)
minetest.register_craftitem("caverealms:angler_rod_baited", {
description = "Baited Pro Fishing Rod",
inventory_image = "caverealms_angler_rod_baited.png",
wield_image = "caverealms_angler_rod_weild.png",
stack_max = 1,
liquids_pointable = true,
on_use = function (itemstack, user, pointed_thing)
if pointed_thing.type ~= "node" then
return
end
local node = minetest.get_node(pointed_thing.under).name
if (node == "default:water_source"
or node == "default:river_water_source")
and math.random(1, 100) < 35 then
local type = fish[math.random(1, #fish)][1]
local inv = user:get_inventory()
if inv:room_for_item("main", {name = type}) then
inv:add_item("main", {name = type})
if (math.random() < 0.6) then
return ItemStack("caverealms:angler_rod_baited")
else
return ItemStack("caverealms:angler_rod")
end
else
minetest.chat_send_player(user:get_player_name(),
"Inventory full, Fish Got Away!")
end
end
end,
})
minetest.register_craft({
type = "shapeless",
output = "caverealms:angler_rod_baited",
recipe = {"caverealms:angler_rod", "caverealms:glow_bait"},
})
end

View file

@ -0,0 +1 @@
A mod for Minetest to add underground realms.

View file

@ -0,0 +1,19 @@
Biome #, Biome name, "floor node"
0, None
1, Moss, "caverealms:stone_with_moss"
2, Fungal, "caverealms:stone_with_lichen"
3, Algae, "caverealms:stone_with_algae"
4, Glaciated, "caverealms:thin_ice"
The following are "deep realms"
5, Deep Glaciated, "default:ice"
6, DM, "caverealms:hot_cobble"
7, Salt Crystal, "caverealms:stone_with_salt"
8, Glow Obsidian, "caverealms:glow_obsidian"
OR "caverealms:glow_obsidian2"
9, Coal, "default:coalblock"
OR "caverealms:coal_dust"
OR "default:desert_sand"

View file

@ -0,0 +1,16 @@
mobs:spawn({
name = "mobs_monster:dungeon_master",
nodes = {"caverealms:hot_cobble"},
max_light = 12,
min_light = 0,
chance = 7000,
active_object_count = 2,
max_height = -8000,
on_spawn = function(self, pos)
self.hp_max = 70
self.health = 70
self.damage = 5
self.shoot_interval = 1.5
self.dogshoot_switch = 0
end
})

View file

@ -0,0 +1,409 @@
local H_LAG = caverealms.config.h_lag --15 --max height for stalagmites
local H_LAC = caverealms.config.h_lac --20 --...stalactites
local H_CRY = caverealms.config.h_cry --9 --max height of glow crystals
local H_CLAC = caverealms.config.h_clac --13 --max height of glow crystal stalactites
function caverealms:above_solid(x,y,z,area,data)
local c_air = minetest.get_content_id("air")
local ai = area:index(x,y+1,z-3)
if data[ai] == c_air then
return false
else
return true
end
end
function caverealms:below_solid(x,y,z,area,data)
local c_air = minetest.get_content_id("air")
local ai = area:index(x,y-1,z-3)
if data[ai] == c_air then
return false
else
return true
end
end
--stalagmite spawner
function caverealms:stalagmite(x,y,z, area, data)
if not caverealms:below_solid(x,y,z,area,data) then
return
end
--contest ids
local c_stone = minetest.get_content_id("default:stone")
local top = math.random(6,H_LAG) --grab a random height for the stalagmite
for j = 0, top do --y
for k = -3, 3 do
for l = -3, 3 do
if j == 0 then
if k*k + l*l <= 9 then
local vi = area:index(x+k, y+j, z+l-3)
data[vi] = c_stone
end
elseif j <= top/5 then
if k*k + l*l <= 4 then
local vi = area:index(x+k, y+j, z+l-3)
data[vi] = c_stone
end
elseif j <= top/5 * 3 then
if k*k + l*l <= 1 then
local vi = area:index(x+k, y+j, z+l-3)
data[vi] = c_stone
end
else
local vi = area:index(x, y+j, z-3)
data[vi] = c_stone
end
end
end
end
end
--stalactite spawner
function caverealms:stalactite(x,y,z, area, data)
if not caverealms:above_solid(x,y,z,area,data) then
return
end
--contest ids
local c_stone = minetest.get_content_id("default:stone")--("caverealms:limestone")
local bot = math.random(-H_LAC, -6) --grab a random height for the stalagmite
for j = bot, 0 do --y
for k = -3, 3 do
for l = -3, 3 do
if j >= -1 then
if k*k + l*l <= 9 then
local vi = area:index(x+k, y+j, z+l-3)
data[vi] = c_stone
end
elseif j >= bot/5 then
if k*k + l*l <= 4 then
local vi = area:index(x+k, y+j, z+l-3)
data[vi] = c_stone
end
elseif j >= bot/5 * 3 then
if k*k + l*l <= 1 then
local vi = area:index(x+k, y+j, z+l-3)
data[vi] = c_stone
end
else
local vi = area:index(x, y+j, z-3)
data[vi] = c_stone
end
end
end
end
end
--glowing crystal stalagmite spawner
function caverealms:crystal_stalagmite(x,y,z, area, data, biome)
if not caverealms:below_solid(x,y,z,area,data) then
return
end
--contest ids
local c_stone = minetest.get_content_id("default:stone")
local c_crystal = minetest.get_content_id("caverealms:glow_crystal")
local c_crystore = minetest.get_content_id("caverealms:glow_ore")
local c_emerald = minetest.get_content_id("caverealms:glow_emerald")
local c_emore = minetest.get_content_id("caverealms:glow_emerald_ore")
local c_mesecry = minetest.get_content_id("caverealms:glow_mese")
local c_meseore = minetest.get_content_id("default:stone_with_mese")
local c_ruby = minetest.get_content_id("caverealms:glow_ruby")
local c_rubore = minetest.get_content_id("caverealms:glow_ruby_ore")
local c_ameth = minetest.get_content_id("caverealms:glow_amethyst")
local c_amethore = minetest.get_content_id("caverealms:glow_amethyst_ore")
local c_ice = minetest.get_content_id("default:ice")
local c_thinice = minetest.get_content_id("caverealms:thin_ice")
--for randomness
local mode = 1
if math.random(15) == 1 then
mode = 2
end
if biome == 3 then
if math.random(25) == 1 then
mode = 2
else
mode = 1
end
end
if biome == 4 or biome == 5 then
if math.random(3) == 1 then
mode = 2
end
end
local stalids = {
{ {c_crystore, c_crystal}, {c_emore, c_emerald} },
{ {c_emore, c_emerald}, {c_crystore, c_crystal} },
{ {c_emore, c_emerald}, {c_meseore, c_mesecry} },
{ {c_ice, c_thinice}, {c_crystore, c_crystal}},
{ {c_ice, c_thinice}, {c_crystore, c_crystal}},
{ {c_rubore, c_ruby}, {c_meseore, c_mesecry}},
{ {c_crystore, c_crystal}, {c_rubore, c_ruby} },
{ {c_rubore, c_ruby}, {c_emore, c_emerald}},
{ {c_amethore, c_ameth}, {c_meseore, c_mesecry} },
}
local nid_a
local nid_b
local nid_s = c_stone --stone base, will be rewritten to ice in certain biomes
if biome > 3 and biome < 6 then
if mode == 1 then
nid_a = c_ice
nid_b = c_thinice
nid_s = c_ice
else
nid_a = c_crystore
nid_b = c_crystal
end
elseif mode == 1 then
nid_a = stalids[biome][1][1]
nid_b = stalids[biome][1][2]
else
nid_a = stalids[biome][2][1]
nid_b = stalids[biome][2][2]
end
local top = math.random(5,H_CRY) --grab a random height for the stalagmite
for j = 0, top do --y
for k = -3, 3 do
for l = -3, 3 do
if j == 0 then
if k*k + l*l <= 9 then
local vi = area:index(x+k, y+j, z+l-3)
data[vi] = nid_s
end
elseif j <= top/5 then
if k*k + l*l <= 4 then
local vi = area:index(x+k, y+j, z+l-3)
data[vi] = nid_a
end
elseif j <= top/5 * 3 then
if k*k + l*l <= 1 then
local vi = area:index(x+k, y+j, z+l-3)
data[vi] = nid_b
end
else
local vi = area:index(x, y+j, z-3)
data[vi] = nid_b
end
end
end
end
end
--crystal stalactite spawner
function caverealms:crystal_stalactite(x,y,z, area, data, biome)
if not caverealms:above_solid(x,y,z,area,data) then
return
end
--contest ids
local c_stone = minetest.get_content_id("default:stone")
local c_crystore = minetest.get_content_id("caverealms:glow_ore")
local c_crystal = minetest.get_content_id("caverealms:glow_crystal")
local c_emerald = minetest.get_content_id("caverealms:glow_emerald")
local c_emore = minetest.get_content_id("caverealms:glow_emerald_ore")
local c_mesecry = minetest.get_content_id("caverealms:glow_mese")
local c_meseore = minetest.get_content_id("default:stone_with_mese")
local c_ruby = minetest.get_content_id("caverealms:glow_ruby")
local c_rubore = minetest.get_content_id("caverealms:glow_ruby_ore")
local c_ameth = minetest.get_content_id("caverealms:glow_amethyst")
local c_amethore = minetest.get_content_id("caverealms:glow_amethyst_ore")
local c_ice = minetest.get_content_id("default:ice")
local c_thinice = minetest.get_content_id("caverealms:hanging_thin_ice")
--for randomness
local mode = 1
if math.random(15) == 1 then
mode = 2
end
if biome == 3 then
if math.random(25) == 1 then
mode = 2
else
mode = 1
end
end
if biome == 4 or biome == 5 then
if math.random(3) == 1 then
mode = 2
end
end
local stalids = {
{ {c_crystore, c_crystal}, {c_emore, c_emerald} },
{ {c_emore, c_emerald}, {c_crystore, c_crystal} },
{ {c_emore, c_emerald}, {c_meseore, c_mesecry} },
{ {c_ice, c_thinice}, {c_crystore, c_crystal}},
{ {c_ice, c_thinice}, {c_crystore, c_crystal}},
{ {c_rubore, c_ruby}, {c_meseore, c_mesecry}},
{ {c_crystore, c_crystal}, {c_rubore, c_ruby} },
{ {c_rubore, c_ruby}, {c_emore, c_emerald}},
{ {c_amethore, c_ameth}, {c_meseore, c_mesecry} },
}
local nid_a
local nid_b
local nid_s = c_stone --stone base, will be rewritten to ice in certain biomes
if biome > 3 and biome < 6 then
if mode == 1 then
nid_a = c_ice
nid_b = c_thinice
nid_s = c_ice
else
nid_a = c_crystore
nid_b = c_crystal
end
elseif mode == 1 then
nid_a = stalids[biome][1][1]
nid_b = stalids[biome][1][2]
else
nid_a = stalids[biome][2][1]
nid_b = stalids[biome][2][2]
end
local bot = math.random(-H_CLAC, -6) --grab a random height for the stalagmite
for j = bot, 0 do --y
for k = -3, 3 do
for l = -3, 3 do
if j >= -1 then
if k*k + l*l <= 9 then
local vi = area:index(x+k, y+j, z+l-3)
data[vi] = nid_s
end
elseif j >= bot/5 then
if k*k + l*l <= 4 then
local vi = area:index(x+k, y+j, z+l-3)
data[vi] = nid_a
end
elseif j >= bot/5 * 3 then
if k*k + l*l <= 1 then
local vi = area:index(x+k, y+j, z+l-3)
data[vi] = nid_b
end
else
local vi = area:index(x, y+j, z-3)
data[vi] = nid_b
end
end
end
end
end
--glowing crystal stalagmite spawner
function caverealms:salt_stalagmite(x,y,z, area, data, biome)
if not caverealms:below_solid(x,y,z,area,data) then
return
end
--contest ids
local c_stone = minetest.get_content_id("default:stone")
local c_salt = minetest.get_content_id("caverealms:salt_crystal")
local scale = math.random(2, 4)
if scale == 2 then
for j = -3, 3 do
for k = -3, 3 do
local vi = area:index(x+j, y, z+k)
data[vi] = c_stone
if math.abs(j) ~= 3 and math.abs(k) ~= 3 then
local vi = area:index(x+j, y+1, z+k)
data[vi] = c_stone
end
end
end
else
for j = -4, 4 do
for k = -4, 4 do
local vi = area:index(x+j, y, z+k)
data[vi] = c_stone
if math.abs(j) ~= 4 and math.abs(k) ~= 4 then
local vi = area:index(x+j, y+1, z+k)
data[vi] = c_stone
end
end
end
end
for j = 2, scale + 2 do --y
for k = -2, scale - 2 do
for l = -2, scale - 2 do
local vi = area:index(x+k, y+j, z+l)
data[vi] = c_salt -- make cube
end
end
end
end
--function to create giant 'shrooms
function caverealms:giant_shroom(x, y, z, area, data)
if not caverealms:below_solid(x,y,z,area,data) then
return
end
local c_cap
local c_stem
--as usual, grab the content ID's
if minetest.get_modpath("ethereal") then
c_stem = minetest.get_content_id("ethereal:mushroom_trunk")
c_cap = minetest.get_content_id("ethereal:mushroom")
else
c_stem = minetest.get_content_id("caverealms:mushroom_stem")
c_cap = minetest.get_content_id("caverealms:mushroom_cap")
end
local c_gills = minetest.get_content_id("caverealms:mushroom_gills")
z = z - 5
--cap
for k = -5, 5 do
for l = -5, 5 do
if k*k + l*l <= 25 then
local vi = area:index(x+k, y+5, z+l)
data[vi] = c_cap
end
if k*k + l*l <= 16 then
local vi = area:index(x+k, y+6, z+l)
data[vi] = c_cap
vi = area:index(x+k, y+5, z+l)
data[vi] = c_gills
end
if k*k + l*l <= 9 then
local vi = area:index(x+k, y+7, z+l)
data[vi] = c_cap
end
if k*k + l*l <= 4 then
local vi = area:index(x+k, y+8, z+l)
data[vi] = c_cap
end
end
end
--stem
for j = 0, 5 do
for k = -1,1 do
local vi = area:index(x+k, y+j, z)
data[vi] = c_stem
if k == 0 then
local ai = area:index(x, y+j, z+1)
data[ai] = c_stem
ai = area:index(x, y+j, z-1)
data[ai] = c_stem
end
end
end
end

View file

@ -0,0 +1,24 @@
-- caverealms v.0.8 by HeroOfTheWinds
-- original cave code modified from paramat's subterrain
-- For Minetest 0.4.8 stable
-- Depends default
-- License: code WTFPL
caverealms = {} --create a container for functions and constants
--grab a shorthand for the filepath of the mod
local modpath = minetest.get_modpath(minetest.get_current_modname())
--load companion lua files
dofile(modpath.."/config.lua") --configuration file; holds various constants
dofile(modpath.."/crafting.lua") --crafting recipes
dofile(modpath.."/nodes.lua") --node definitions
dofile(modpath.."/functions.lua") --function definitions
dofile(modpath.."/plants.lua")
dofile(modpath.."/biomes.lua")
if minetest.get_modpath("mobs_monster") then
if caverealms.config.dm_spawn == true then
dofile(modpath.."/dungeon_master.lua") --special DMs for DM's Lair biome
end
end

View file

@ -0,0 +1 @@
name = caverealms

View file

@ -0,0 +1,521 @@
-- CaveRealms nodes.lua
--NODES--
--glowing crystal
minetest.register_node("caverealms:glow_crystal", {
description = "Glow Sapphire",
tiles = {"caverealms_glow_crystal.png"},
is_ground_content = true,
groups = {cracky=3},
sounds = default.node_sound_glass_defaults(),
light_source = 13,
paramtype = "light",
use_texture_alpha = true,
drawtype = "glasslike",
sunlight_propagates = true,
})
--glowing emerald
minetest.register_node("caverealms:glow_emerald", {
description = "Glow Emerald",
tiles = {"caverealms_glow_emerald.png"},
is_ground_content = true,
groups = {cracky=3},
sounds = default.node_sound_glass_defaults(),
light_source = 13,
paramtype = "light",
use_texture_alpha = true,
drawtype = "glasslike",
sunlight_propagates = true,
})
--glowing mese crystal blocks
minetest.register_node("caverealms:glow_mese", {
description = "Glow Mese Crystal",
tiles = {"caverealms_glow_mese.png"},
is_ground_content = true,
groups = {cracky=3},
sounds = default.node_sound_glass_defaults(),
light_source = 13,
paramtype = "light",
use_texture_alpha = true,
drawtype = "glasslike",
sunlight_propagates = true,
})
--glowing ruby
minetest.register_node("caverealms:glow_ruby", {
description = "Glow Ruby",
tiles = {"caverealms_glow_ruby.png"},
is_ground_content = true,
groups = {cracky=3},
sounds = default.node_sound_glass_defaults(),
light_source = 13,
paramtype = "light",
use_texture_alpha = true,
drawtype = "glasslike",
sunlight_propagates = true,
})
--glowing amethyst
minetest.register_node("caverealms:glow_amethyst", {
description = "Glow Amethyst",
tiles = {"caverealms_glow_amethyst.png"},
is_ground_content = true,
groups = {cracky=3},
sounds = default.node_sound_glass_defaults(),
light_source = 13,
paramtype = "light",
use_texture_alpha = true,
drawtype = "glasslike",
sunlight_propagates = true,
})
--embedded crystal
minetest.register_node("caverealms:glow_ore", {
description = "Glow Crystal Ore",
tiles = {"caverealms_glow_ore.png"},
is_ground_content = true,
groups = {cracky=2},
sounds = default.node_sound_glass_defaults(),
light_source = 10,
paramtype = "light",
})
--embedded emerald
minetest.register_node("caverealms:glow_emerald_ore", {
description = "Glow Emerald Ore",
tiles = {"caverealms_glow_emerald_ore.png"},
is_ground_content = true,
groups = {cracky=2},
sounds = default.node_sound_glass_defaults(),
light_source = 10,
paramtype = "light",
})
--embedded ruby
minetest.register_node("caverealms:glow_ruby_ore", {
description = "Glow Ruby Ore",
tiles = {"caverealms_glow_ruby_ore.png"},
is_ground_content = true,
groups = {cracky=2},
sounds = default.node_sound_glass_defaults(),
light_source = 10,
paramtype = "light",
})
--embedded amethyst
minetest.register_node("caverealms:glow_amethyst_ore", {
description = "Glow Amethyst Ore",
tiles = {"caverealms_glow_amethyst_ore.png"},
is_ground_content = true,
groups = {cracky=2},
sounds = default.node_sound_glass_defaults(),
light_source = 10,
paramtype = "light",
})
--thin (transparent) ice
minetest.register_node("caverealms:thin_ice", {
description = "Thin Ice",
tiles = {"caverealms_thin_ice.png"},
is_ground_content = true,
groups = {cracky=3},
sounds = default.node_sound_glass_defaults(),
use_texture_alpha = true,
drawtype = "glasslike",
sunlight_propagates = true,
freezemelt = "default:water_source",
paramtype = "light",
})
--salt crystal
minetest.register_node("caverealms:salt_crystal", {
description = "Salt Crystal",
tiles = {"caverealms_salt_crystal.png"},
is_ground_content = true,
groups = {cracky=2},
sounds = default.node_sound_glass_defaults(),
light_source = 11,
paramtype = "light",
use_texture_alpha = true,
drawtype = "glasslike",
sunlight_propagates = true,
})
--glowing crystal gem
minetest.register_node("caverealms:glow_gem", {
description = "Glow Gem",
tiles = {"caverealms_glow_gem.png"},
inventory_image = "caverealms_glow_gem.png",
wield_image = "caverealms_glow_gem.png",
is_ground_content = true,
groups = {cracky = 3, oddly_breakable_by_hand = 1, attached_node = 1},
sounds = default.node_sound_glass_defaults(),
light_source = 11,
paramtype = "light",
drawtype = "plantlike",
walkable = false,
buildable_to = true,
visual_scale = 0.75,
selection_box = {
type = "fixed",
fixed = {-0.5, -0.5, -0.5, 0.5, -5/16, 0.5},
}
})
--glowing salt gem
minetest.register_node("caverealms:salt_gem", {
description = "Salt Gem",
tiles = {"caverealms_salt_gem.png"},
inventory_image = "caverealms_salt_gem.png",
wield_image = "caverealms_salt_gem.png",
is_ground_content = true,
groups = {cracky = 3, oddly_breakable_by_hand = 1, attached_node = 1},
sounds = default.node_sound_glass_defaults(),
light_source = 11,
paramtype = "light",
drawtype = "plantlike",
walkable = false,
buildable_to = true,
visual_scale = 0.75,
selection_box = {
type = "fixed",
fixed = {-0.5, -0.5, -0.5, 0.5, -5/16, 0.5},
}
})
--stone spike
minetest.register_node("caverealms:spike", {
description = "Stone Spike",
tiles = {"caverealms_spike.png"},
inventory_image = "caverealms_spike.png",
wield_image = "caverealms_spike.png",
is_ground_content = true,
groups = {cracky = 3, oddly_breakable_by_hand = 1, attached_node = 1},
sounds = default.node_sound_stone_defaults(),
light_source = 3,
paramtype = "light",
drawtype = "plantlike",
walkable = false,
buildable_to = true,
visual_scale = 0.75,
selection_box = {
type = "fixed",
fixed = {-0.5, -0.5, -0.5, 0.5, -5/16, 0.5},
}
})
--upward pointing icicle
minetest.register_node("caverealms:icicle_up", {
description = "Icicle",
tiles = {"caverealms_icicle_up.png"},
inventory_image = "caverealms_icicle_up.png",
wield_image = "caverealms_icicle_up.png",
is_ground_content = true,
groups = {cracky=3, oddly_breakable_by_hand=1},
sounds = default.node_sound_glass_defaults(),
light_source = 8,
paramtype = "light",
drawtype = "plantlike",
walkable = false,
buildable_to = true,
visual_scale = 1.0,
selection_box = {
type = "fixed",
fixed = {-0.5, -0.5, -0.5, 0.5, -5/16, 0.5},
},
})
--downward pointing icicle
minetest.register_node("caverealms:icicle_down", {
description = "Icicle",
tiles = {"caverealms_icicle_down.png"},
inventory_image = "caverealms_icicle_down.png",
wield_image = "caverealms_icicle_down.png",
is_ground_content = true,
groups = {cracky=3, oddly_breakable_by_hand=1},
sounds = default.node_sound_glass_defaults(),
light_source = 8,
paramtype = "light",
drawtype = "plantlike",
walkable = false,
buildable_to = true,
visual_scale = 1.0,
selection_box = {
type = "fixed",
fixed = {-0.5, -0.5, -0.5, 0.5, -5/16, 0.5},
},
})
--cave mossy cobble - bluish?
minetest.register_node("caverealms:stone_with_moss", {
description = "Cave Stone with Moss",
tiles = {"default_cobble.png^caverealms_moss.png", "default_cobble.png", "default_cobble.png^caverealms_moss_side.png"},
is_ground_content = true,
groups = {crumbly=1, cracky=3},
drop = 'default:cobble',
sounds = default.node_sound_dirt_defaults({
footstep = {name="default_grass_footstep", gain=0.25},
}),
})
--cave lichen-covered cobble - purple-ish
minetest.register_node("caverealms:stone_with_lichen", {
description = "Cave Stone with Lichen",
tiles = {"default_cobble.png^caverealms_lichen.png", "default_cobble.png", "default_cobble.png^caverealms_lichen_side.png"},
is_ground_content = true,
groups = {crumbly=1, cracky=3},
drop = 'default:cobble',
sounds = default.node_sound_dirt_defaults({
footstep = {name="default_grass_footstep", gain=0.25},
}),
})
--cave algae-covered cobble - yellow-ish
minetest.register_node("caverealms:stone_with_algae", {
description = "Cave Stone with Algae",
tiles = {"default_cobble.png^caverealms_algae.png", "default_cobble.png", "default_cobble.png^caverealms_algae_side.png"},
is_ground_content = true,
groups = {crumbly=1, cracky=3},
drop = 'default:cobble',
sounds = default.node_sound_dirt_defaults({
footstep = {name="default_grass_footstep", gain=0.25},
}),
})
--tiny-salt-crystal-covered cobble - pink-ish
minetest.register_node("caverealms:stone_with_salt", {
description = "Salt Crystal",
tiles = {"caverealms_salty2.png"},
light_source = 9,
paramtype = "light",
use_texture_alpha = true,
drawtype = "glasslike",
sunlight_propagates = true,
is_ground_content = true,
groups = {cracky=3},
sounds = default.node_sound_glass_defaults(),
})
--Hot Cobble - cobble with lava instead of mortar XD
minetest.register_node("caverealms:hot_cobble", {
description = "Hot Cobble",
tiles = {"caverealms_hot_cobble.png"},
is_ground_content = true,
groups = {cracky=1, hot=1, unbreakable = 1, stone = 1},
damage_per_second = 1,
light_source = 3,
paramtype = "light",
sounds = default.node_sound_stone_defaults(),
})
--Glow Obsidian
minetest.register_node("caverealms:glow_obsidian", {
description = "Glowing Obsidian",
tiles = {"caverealms_glow_obsidian.png"},
is_ground_content = true,
groups = {cracky=1, level=2},
light_source = 7,
paramtype = "light",
sounds = default.node_sound_stone_defaults(),
})
--Glow Obsidian 2 - has traces of lava
minetest.register_node("caverealms:glow_obsidian_2", {
description = "Hot Glowing Obsidian",
tiles = {"caverealms_glow_obsidian2.png"},
is_ground_content = true,
groups = {cracky=1, hot=1, level=2},
light_source = 9,
paramtype = "light",
sounds = default.node_sound_stone_defaults(),
})
--Glow Obsidian Bricks
minetest.register_node("caverealms:glow_obsidian_brick", {
description = "Glow Obsidian Brick",
tiles = {"caverealms_glow_obsidian_brick.png"},
light_source = 7,
groups = {cracky = 1, level = 2},
sounds = default.node_sound_stone_defaults(),
})
minetest.register_node("caverealms:glow_obsidian_brick_2", {
description = "Glow Obsidian Brick",
tiles = {"caverealms_glow_obsidian_brick_2.png"},
light_source = 9,
groups = {cracky = 1, level = 2},
sounds = default.node_sound_stone_defaults(),
})
--Glow Obsidian Stairs/Slabs
stairs.register_stair_and_slab(
"glow_obsidian_brick",
"caverealms:glow_obsidian_brick",
{cracky = 1, level = 2},
{"caverealms_glow_obsidian_brick.png"},
"Glow Obsidian Brick Stair",
"Glow Obsidian Brick Slab",
default.node_sound_stone_defaults())
stairs.register_stair_and_slab(
"glow_obsidian_brick_2",
"caverealms:glow_obsidian_brick_2",
{cracky = 1, level = 2},
{"caverealms_glow_obsidian_brick_2.png"},
"Glow Obsidian Brick Stair",
"Glow Obsidian Brick Slab",
default.node_sound_stone_defaults())
--Glow Obsidian Glass
minetest.register_node("caverealms:glow_obsidian_glass", {
description = "Glow Obsidian Glass",
drawtype = "glasslike_framed_optional",
tiles = {"caverealms_glow_obsidian_glass.png", "default_obsidian_glass_detail.png"},
paramtype = "light",
light_source = 13,
sunlight_propagates = true,
groups = {cracky = 3},
sounds = default.node_sound_glass_defaults(),
})
--Coal Dust
minetest.register_node("caverealms:coal_dust", {
description = "Coal Dust",
tiles = {"caverealms_coal_dust.png"},
is_ground_content = true,
groups = {crumbly=3, falling_node=1, sand=1},
sounds = default.node_sound_sand_defaults(),
})
--glow worms
minetest.register_node("caverealms:glow_worm", {
description = "Blue Glow Worms",
tiles = {"caverealms_glow_worm.png"},
inventory_image = "caverealms_glow_worm.png",
wield_image = "caverealms_glow_worm.png",
is_ground_content = true,
groups = {oddly_breakable_by_hand=3},
light_source = 9,
paramtype = "light",
drawtype = "plantlike",
walkable = false,
buildable_to = true,
visual_scale = 1.0,
selection_box = {
type = "fixed",
fixed = {-1/6, -1/2, -1/6, 1/6, 1/2, 1/6},
},
})
minetest.register_node("caverealms:glow_worm_green", {
description = "Green Glow Worms",
tiles = {"caverealms_glow_worm_green.png"},
inventory_image = "caverealms_glow_worm_green.png",
wield_image = "caverealms_glow_worm_green.png",
is_ground_content = true,
groups = {oddly_breakable_by_hand=3},
light_source = 9,
paramtype = "light",
drawtype = "plantlike",
walkable = false,
buildable_to = true,
visual_scale = 1.0,
selection_box = {
type = "fixed",
fixed = {-1/6, -1/2, -1/6, 1/6, 1/2, 1/6},
},
})
minetest.register_node("caverealms:fire_vine", {
description = "Fire Vine",
tiles = {"caverealms_fire_vine.png"},
inventory_image = "caverealms_fire_vine.png",
wield_image = "caverealms_fire_vine.png",
is_ground_content = true,
damage_per_second = 1,
groups = {oddly_breakable_by_hand=3},
light_source = 9,
paramtype = "light",
drawtype = "plantlike",
walkable = false,
buildable_to = true,
visual_scale = 1.0,
selection_box = {
type = "fixed",
fixed = {-1/6, -1/2, -1/6, 1/6, 1/2, 1/6},
},
})
--define special flame so that it does not expire
minetest.register_node("caverealms:constant_flame", {
description = "Fire",
drawtype = "plantlike",
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",
light_source = 14,
groups = {igniter=2, dig_immediate=3, hot=3, not_in_creative_inventory=1},
paramtype = "light",
drop = '',
walkable = false,
buildable_to = true,
floodable = true,
damage_per_second = 4,
})
--dungeon master statue (nodebox)
minetest.register_node("caverealms:dm_statue", {
description = "Dungeon Master Statue",
tiles = {
"caverealms_dm_stone.png",
"caverealms_dm_stone.png",
"caverealms_dm_stone.png",
"caverealms_dm_stone.png",
"caverealms_dm_stone.png",
"caverealms_stone_eyes.png"
},
drawtype = "nodebox",
paramtype = "light",
paramtype2 = "facedir",
groups = {cracky=2},
node_box = {
type = "fixed",
fixed = {
{-0.4375, -0.5, -0.4375, 0.4375, -0.3125, 0.4375}, -- NodeBox1
{-0.25, -0.125, -0.1875, 0.25, 0.5, 0.1875}, -- NodeBox2
{-0.375, 0, -0.125, -0.25, 0.4375, 0.125}, -- NodeBox3
{0.25, 0.125, -0.4375, 0.375, 0.375, 0.1875}, -- NodeBox4
{-0.25, -0.5, -0.125, -0.125, -0.125, 0.125}, -- NodeBox5
{0.125, -0.3125, -0.125, 0.25, 0, 0.125}, -- NodeBox6
}
},
selection_box = {
type = "regular"
}
})
-- Compatibility
minetest.register_alias("caverealms:hanging_thin_ice", "caverealms:thin_ice")
minetest.register_alias("caverealms:spike_2", "caverealms:spike")
minetest.register_alias("caverealms:spike_3", "caverealms:spike")
minetest.register_alias("caverealms:spike_4", "caverealms:spike")
minetest.register_alias("caverealms:spike_5", "caverealms:spike")
minetest.register_alias("caverealms:salt_gem_2", "caverealms:salt_gem")
minetest.register_alias("caverealms:salt_gem_3", "caverealms:salt_gem")
minetest.register_alias("caverealms:salt_gem_4", "caverealms:salt_gem")
minetest.register_alias("caverealms:salt_gem_5", "caverealms:salt_gem")
minetest.register_alias("caverealms:glow_gem_2", "caverealms:glow_gem")
minetest.register_alias("caverealms:glow_gem_3", "caverealms:glow_gem")
minetest.register_alias("caverealms:glow_gem_4", "caverealms:glow_gem")
minetest.register_alias("caverealms:glow_gem_5", "caverealms:glow_gem")

View file

@ -0,0 +1,191 @@
-- Cavrealms plants and trees for lichen, moss and algae biomes
-- Lichen biome
-- glowing fungi
minetest.register_node("caverealms:fungus", {
description = "Glowing Fungus",
tiles = {"caverealms_fungi.png"},
inventory_image = "caverealms_fungi.png",
wield_image = "caverealms_fungi.png",
is_ground_content = true,
groups = {oddly_breakable_by_hand = 3, attached_node = 1, flammable = 1},
light_source = 5,
paramtype = "light",
drawtype = "plantlike",
walkable = false,
buildable_to = true,
visual_scale = 1.0,
selection_box = {
type = "fixed",
fixed = {-0.5, -0.5, -0.5, 0.5, -5/16, 0.5},
},
})
-- mycena mushroom
minetest.register_node("caverealms:mycena", {
description = "Mycena Mushroom",
tiles = {"caverealms_mycena.png"},
inventory_image = "caverealms_mycena.png",
wield_image = "caverealms_mycena.png",
is_ground_content = true,
groups = {oddly_breakable_by_hand = 3, attached_node = 1, flammable = 1},
light_source = 6,
paramtype = "light",
drawtype = "plantlike",
walkable = false,
buildable_to = true,
visual_scale = 1.0,
selection_box = {
type = "fixed",
fixed = {-0.5, -0.5, -0.5, 0.5, -5/16, 0.5},
},
})
-- giant mushroom
if minetest.get_modpath("ethereal") then
minetest.register_alias("caverealms:mushroom_cap", "ethereal:mushroom")
minetest.register_alias("caverealms:mushroom_stem", "ethereal:mushroom_trunk")
else
-- stem
minetest.register_node("caverealms:mushroom_stem", {
description = "Giant Mushroom Stem",
tiles = {"caverealms_mushroom_stem.png"},
is_ground_content = true,
groups = {choppy=2, oddly_breakable_by_hand=1},
})
-- cap
minetest.register_node("caverealms:mushroom_cap", {
description = "Giant Mushroom Cap",
tiles = {"caverealms_mushroom_cap.png"},
is_ground_content = true,
groups = {choppy=2, oddly_breakable_by_hand=1,},
drop = {
max_items = 1,
items = {
{items = {"caverealms:mushroom_sapling"}, rarity = 20},
{items = {"caverealms:mushroom_cap"}}
}
},
})
-- sapling
minetest.register_node("caverealms:mushroom_sapling", {
description = "Mushroom Tree Sapling",
drawtype = "plantlike",
tiles = {"caverealms_mushroom_sapling.png"},
paramtype = "light",
sunlight_propagates = true,
is_ground_content = false,
walkable = false,
selection_box = {
type = "fixed",
fixed = {-4 / 16, -0.5, -4 / 16, 4 / 16, 7 / 16, 4 / 16}
},
groups = {snappy = 2, dig_immediate = 3, flammable = 2},
sounds = default.node_sound_leaves_defaults(),
})
end
-- gills
minetest.register_node("caverealms:mushroom_gills", {
description = "Giant Mushroom Gills",
tiles = {"caverealms_mushroom_gills.png"},
is_ground_content = true,
light_source = 10,
walkable = false,
groups = {choppy=2, oddly_breakable_by_hand=1},
drawtype = "plantlike",
paramtype = "light",
})
-- Saplings
-- grow trees
local add_tree = function (pos, ofx, ofy, ofz, schem)
if not schem then
print ("Schematic not found")
return
end
minetest.swap_node(pos, {name = "air"})
minetest.place_schematic(
{x = pos.x - ofx, y = pos.y - ofy, z = pos.z - ofz},
schem, 0, nil, false)
end
local path = minetest.get_modpath("caverealms").."/schematics/"
-- giant mushrooms
function grow_caverealms_mushroom(pos)
add_tree(pos, 5, 0, 5, path .. "shroom.mts")
end
-- height check
local function enough_height(pos, height)
local nod = minetest.line_of_sight(
{x = pos.x, y = pos.y + 1, z = pos.z},
{x = pos.x, y = pos.y + height, z = pos.z})
if not nod then
return false
else
return true
end
end
minetest.register_abm({
label = "Caverealms grow sapling",
nodenames = {"ethereal:mushroom_sapling", "caverealms:mushroom_sapling"},
interval = 10,
chance = 50,
catch_up = false,
action = function(pos, node)
local light_level = minetest.get_node_light(pos)
-- check light level
if not light_level or light_level > 10 then
return
end
-- get node under sapling
local under = minetest.get_node({x = pos.x, y = pos.y - 1, z = pos.z}).name
-- check if registered
if not minetest.registered_nodes[node.name] then
return
end
-- ethereal sapling on lichen stone
if node.name == "ethereal:mushroom_sapling"
and under == "caverealms:stone_with_lichen"
and enough_height(pos, 10) then
grow_caverealms_mushroom(pos)
-- caverealms sapling on lichen stone
elseif node.name == "caverealms:mushroom_sapling"
and under == "caverealms:stone_with_lichen"
and enough_height(pos, 10) then
grow_caverealms_mushroom(pos)
end
end,
})
-- spread moss/lichen/algae to nearby cobblestone
minetest.register_abm({
label = "Caverealms stone spread",
nodenames = {
"caverealms:stone_with_moss",
"caverealms:stone_with_lichen",
"caverealms:stone_with_algae",
},
neighbors = {"air"},
interval = 16,
chance = 50,
catch_up = false,
action = function(pos, node)
local num = minetest.find_nodes_in_area_under_air(
{x = pos.x - 1, y = pos.y - 2, z = pos.z - 1},
{x = pos.x + 1, y = pos.y + 1, z = pos.z + 1},
"default:cobble")
if #num > 0 then
minetest.set_node(num[math.random(#num)], {name = node.name})
end
end,
})

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 739 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 446 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 273 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 590 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 554 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 325 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 330 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 330 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 330 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 345 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 330 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 351 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 925 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 437 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 754 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 457 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 402 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 402 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 330 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 662 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 679 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 719 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

46
mods/airutils/.luacheckrc Normal file
View file

@ -0,0 +1,46 @@
-- Disable some (non critical) warnings
-- unused = false
unused_args = false
redefined = false
globals = {
"airutils",
}
read_globals = {
"DIR_DELIM",
"ItemStack",
"PseudoRandom",
"basic_machines",
"biomass",
"climate_api",
"core",
"creative",
"default",
"dump",
"emote",
"math",
"mcl_formspec",
"mcl_player",
"minetest",
"player_api",
"signs_lib",
"skins",
"string",
"technic",
"vector",
"wardrobe",
}
-- Per file options
files["airutils_biofuel.lua"] = {
globals = {"basic_machines.grinder_recipes"},
}
files["lib_planes/utilities.lua"] = {
globals = {"player_api.player_attached.?", "mcl_player.player_attached.?"}
}
files["pilot_skin_manager.lua"] = {
globals = {"skins.skin_class.apply_skin_to_player"}
}

37
mods/airutils/LICENSE Normal file
View file

@ -0,0 +1,37 @@
Except for the file "text.lua", adapted from signs_lib from VanessaE,
that is licenced under LGPL 3.0 (see at: https://www.gnu.org/licenses/lgpl-3.0.txt)
all the code is licenced under MIT Licence, as below:
==================================================================================================
MIT License
Copyright (c) 2024 APercy - Alexsandro Percy
Copyright (c) 2019 TheTermos (for code from mobkit at physics_lib.lua)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
==================================================================================================
Media Licence:
CC0-1.0 for all media
the "airutils_explode.ogg" comes from minetest game tnt mod

16
mods/airutils/README.md Normal file
View file

@ -0,0 +1,16 @@
# airutils
Airport Utils for Minetest
This mod is a lib and offers utilities to be used in airports.
We have only 2 items now, but will be expanded as needed.
The first is PAPI (Precision Approach Path Indicator), to guide you in approaching landings. I recommend this article from wikipedia to understand how it works: https://en.wikipedia.org/wiki/Precision ... _indicator
The PAPI is usually located on the left-hand side of the runway at right angles to the runway center line, so, if you want to place it at right side, just right click it to invert lights order.
The second, the tug, allows the repositioning of aircraft that may be blocking the runway or taxiways. In my mods only the owner can fly his own plane, so with this tool, if the person owns the area or the area has no owner, it is possible to move the aircraft without the presence of the pilot. Just click to move, and shift + click to rotate in your direction
Except the media listed bellow, all media licence is CC0
pilot_novaskin_girl.png adapted from Pilot Girl - https://minecraft.novaskin.me/skin/254193054/Pilot-girl
pilot_novaskin_girl_steampunk.png from girl steampunk pilot - https://minecraft.novaskin.me/skin/6190203356577792/girl-steampunk-pilot

View file

@ -0,0 +1,267 @@
----------
--biofuel
----------
local S = airutils.S
local module_name = "airutils"
if core.get_modpath("technic") then
if technic then
technic.register_extractor_recipe({input = {"farming:wheat 33"}, output = "biofuel:biofuel 1"})
technic.register_extractor_recipe({input = {"farming:corn 33"}, output = "biofuel:biofuel 1"})
technic.register_extractor_recipe({input = {"farming:potato 33"}, output = "biofuel:biofuel 1"})
technic.register_extractor_recipe({input = {"default:papyrus 99"}, output = "biofuel:biofuel 1"})
end
end
if core.get_modpath("basic_machines") then
if basic_machines then
basic_machines.grinder_recipes["farming:wheat"] = {50,"biofuel:biofuel",1}
basic_machines.grinder_recipes["farming:corn"] = {50,"biofuel:biofuel",1}
basic_machines.grinder_recipes["farming:potato"] = {50,"biofuel:biofuel",1}
basic_machines.grinder_recipes["default:papyrus"] = {70,"biofuel:biofuel",1}
end
end
if core.get_modpath("default") then
core.register_craft({
output = module_name .. ":biofuel_distiller",
recipe = {
{"default:copper_ingot", "default:copper_ingot", "default:copper_ingot"},
{"default:steel_ingot" , "", "default:steel_ingot"},
{"default:steel_ingot" , "default:steel_ingot", "default:steel_ingot"},
},
})
end
if core.get_modpath("mcl_core") then
core.register_craft({
output = module_name .. ":biofuel_distiller",
recipe = {
{"mcl_copper:copper_ingot", "mcl_copper:copper_ingot", "mcl_copper:copper_ingot"},
{"mcl_core:iron_ingot" , "", "mcl_core:iron_ingot"},
{"mcl_core:iron_ingot" , "mcl_core:iron_ingot", "mcl_core:iron_ingot"},
},
})
end
-- biofuel
local new_gallon_id = "airutils:biofuel"
core.register_craftitem(new_gallon_id,{
description = S("Bio Fuel"),
inventory_image = "airutils_biofuel_inv.png",
})
core.register_craft({
type = "fuel",
recipe = new_gallon_id,
burntime = 50,
})
core.register_alias("biofuel:biofuel", new_gallon_id) --for the old biofuel
local ferment = {
{"default:papyrus", new_gallon_id},
{"farming:wheat", new_gallon_id},
{"farming:corn", new_gallon_id},
{"farming:baked_potato", new_gallon_id},
{"farming:potato", new_gallon_id}
}
local ferment_groups = {'flora', 'leaves', 'flower', 'sapling', 'tree', 'wood', 'stick', 'plant', 'seed',
'leafdecay', 'leafdecay_drop', 'mushroom', 'vines' }
-- distiller
local biofueldistiller_formspec = "size[8,9]"
.. "list[current_name;src;2,1;1,1;]" .. airutils.get_itemslot_bg(2, 1, 1, 1)
.. "list[current_name;dst;5,1;1,1;]" .. airutils.get_itemslot_bg(5, 1, 1, 1)
.. "list[current_player;main;0,5;8,4;]" .. airutils.get_itemslot_bg(0, 5, 8, 4)
.. "listring[current_name;dst]"
.. "listring[current_player;main]"
.. "listring[current_name;src]"
.. "listring[current_player;main]"
.. "image[3.5,1;1,1;gui_furnace_arrow_bg.png^[transformR270]"
core.register_node( module_name .. ":biofuel_distiller", {
description = S("Biofuel Distiller"),
tiles = {"airutils_black.png", "airutils_aluminum.png", "airutils_copper.png" },
drawtype = "mesh",
mesh = "airutils_biofuel_distiller.b3d",
paramtype = "light",
paramtype2 = "facedir",
groups = {
choppy = 2, oddly_breakable_by_hand = 1, flammable = 2
},
legacy_facedir_simple = true,
on_place = core.rotate_node,
on_construct = function(pos)
local meta = core.get_meta(pos)
meta:set_string("formspec", biofueldistiller_formspec)
meta:set_string("infotext", S("Biofuel Distiller"))
meta:set_float("status", 0.0)
local inv = meta:get_inventory()
inv:set_size("src", 1)
inv:set_size("dst", 1)
end,
can_dig = function(pos,player)
local meta = core.get_meta(pos)
local inv = meta:get_inventory()
if not inv:is_empty("dst")
or not inv:is_empty("src") then
return false
end
return true
end,
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
if core.is_protected(pos, player:get_player_name()) then
return 0
end
return stack:get_count()
end,
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
if core.is_protected(pos, player:get_player_name()) then
return 0
end
if listname == "src" then
return stack:get_count()
elseif listname == "dst" then
return 0
end
end,
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
if core.is_protected(pos, player:get_player_name()) then
return 0
end
if to_list == "src" then
return count
elseif to_list == "dst" then
return 0
end
end,
on_metadata_inventory_put = function(pos)
local timer = core.get_node_timer(pos)
timer:start(5)
end,
on_timer = function(pos)
local meta = core.get_meta(pos) ; if not meta then return end
local inv = meta:get_inventory()
-- is barrel empty?
if not inv or inv:is_empty("src") then
meta:set_float("status", 0.0)
meta:set_string("infotext", S("Fuel Distiller"))
return false
end
-- does it contain any of the source items on the list?
local has_item
--normal items
for n = 1, #ferment do
if inv:contains_item("src", ItemStack(ferment[n][1])) then
has_item = n
break
end
end
--groups
local has_group
if not has_item then
local inv_content = inv:get_list("src")
if inv_content then
for k, v in pairs(inv_content) do
local item_name = v:get_name()
for n = 1, #ferment_groups do
if core.get_item_group(item_name, ferment_groups[n]) == 1 then
has_group = n
break
end
end
end
end
end
if not has_item and not has_group then
return false
end
-- is there room for additional fermentation?
if has_item and not inv:room_for_item("dst", ferment[has_item][2]) then
meta:set_string("infotext", S("Fuel Distiller (FULL)"))
return true
end
if has_group and not inv:room_for_item("dst", new_gallon_id) then
meta:set_string("infotext", S("Fuel Distiller (FULL)"))
return true
end
local status = meta:get_float("status")
-- fermenting (change status)
if status < 100 then
meta:set_string("infotext", S("Fuel Distiller @1% done", status))
meta:set_float("status", status + 5)
else
if not has_group then
inv:remove_item("src", ferment[has_item][1])
inv:add_item("dst", ferment[has_item][2])
else
for i,itemstack in pairs(inv:get_list("src")) do
inv:remove_item("src", ItemStack(itemstack:get_name().." 1"))
end
inv:add_item("dst", new_gallon_id)
end
meta:set_float("status", 0,0)
end
if inv:is_empty("src") then
meta:set_float("status", 0.0)
meta:set_string("infotext", S("Fuel Distiller"))
end
return true
end,
})
--lets remove the old one
core.register_node(":".."biofuel:biofuel_distiller", {
groups = {old_biofuel=1},
})
core.register_abm({
nodenames = {"group:old_biofuel"},
interval = 1,
chance = 1,
action = function(pos, node)
--core.remove_node(pos)
core.swap_node(pos,{name = module_name..":biofuel_distiller"})
end,
})

View file

@ -0,0 +1,170 @@
local S = airutils.S
local function check_protection(pos, name)
if core.is_protected(pos, name) then
core.log("action", name
.. " tried to place a PAPI"
.. " at protected position "
.. core.pos_to_string(pos)
)
core.record_protection_violation(pos, name)
return true
end
return false
end
function airutils.PAPIplace(player,pos)
if not player then
return
end
local dir = core.dir_to_facedir(player:get_look_dir())
local player_name = player:get_player_name()
if check_protection(pos, player_name) then
return
end
core.set_node(pos, {name="airutils:papi", param2=dir})
local meta = core.get_meta(pos)
meta:set_string("infotext", S("PAPI") .. "\r" .. S("Owned by: @1", player_name))
meta:set_string("owner", player_name)
meta:set_string("dont_destroy", "false")
return true
end
function airutils.togglePapiSide(pos, node, clicker, itemstack)
local player_name = clicker:get_player_name()
local meta = core.get_meta(pos)
if player_name ~= meta:get_string("owner") then
return
end
local dir=node.param2
if node.name == "airutils:papi_right" then
core.set_node(pos, {name="airutils:papi", param2=dir})
meta:set_string("infotext", S("PAPI") .. " - " .. S("left side") .. "\r" .. S("Owned by: @1",player_name))
elseif node.name == "airutils:papi" then
core.set_node(pos, {name="airutils:papi_right", param2=dir})
meta:set_string("infotext", S("PAPI") .. " - " .. S("right side") .. "\r" .. S("Owned by: @1",player_name))
end
meta:set_string("owner", player_name)
meta:set_string("dont_destroy", "false")
end
airutils.papi_collision_box = {
type = "fixed",
fixed={{-0.5,-0.5,-0.5,0.5,-0.42,0.5},},
}
airutils.papi_selection_box = {
type = "fixed",
fixed={{-0.5,-0.5,-0.5,0.5,1.5,0.5},},
}
airutils.groups_right = {snappy=2,choppy=2,oddly_breakable_by_hand=2,not_in_creative_inventory=1}
airutils.groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2}
-- PAPI node (default left)
core.register_node("airutils:papi",{
description = S("PAPI"),
--inventory_image = "papi.png",
--wield_image = "papi.png",
tiles = {"airutils_black.png", "airutils_u_black.png", "airutils_white.png",
"airutils_metal.png", {name = "airutils_red.png", backface_culling = true},},
groups = airutils.groups,
paramtype2 = "facedir",
paramtype = "light",
drawtype = "mesh",
mesh = "papi.b3d",
visual_scale = 1.0,
light_source = 13,
backface_culling = true,
selection_box = airutils.papi_selection_box,
collision_box = airutils.papi_collision_box,
can_dig = airutils.canDig,
_color = "",
on_destruct = airutils.remove,
on_place = function(itemstack, placer, pointed_thing)
local pos = pointed_thing.above
if airutils.PAPIplace(placer,pos)==true then
itemstack:take_item(1)
return itemstack
else
return
end
end,
on_rightclick=airutils.togglePapiSide,
on_punch = function(pos, node, puncher, pointed_thing)
local player_name = puncher:get_player_name()
local meta = core.get_meta(pos)
if player_name ~= meta:get_string("owner") then
local privs = core.get_player_privs(player_name)
if privs.server == false then
return
end
end
end,
})
function airutils.remove_papi(pos)
--[[
local meta = core.get_meta(pos)
local node = core.get_node(pos)
if node and meta then
local dir=node.param2
if node.name == "airutils:papi_right" then
core.set_node(pos, {name="airutils:papi", param2=dir})
meta:set_string("infotext", "PAPI - left side\rOwned by: "..player_name)
end
meta:set_string("owner", player_name)
meta:set_string("dont_destroy", "false")
if meta:get_string("dont_destroy") == "true" then
-- when swapping it
return
end
end]]--
end
-- PAPI right node
core.register_node("airutils:papi_right",{
description = S("PAPI") .. "_" .. S("right_side"),
tiles = {"airutils_black.png", "airutils_u_black.png", "airutils_white.png",
"airutils_metal.png", {name = "airutils_red.png", backface_culling = true},},
groups = airutils.groups_right,
paramtype2 = "facedir",
paramtype = "light",
drawtype = "mesh",
mesh = "papi_right.b3d",
visual_scale = 1.0,
light_source = 13,
backface_culling = true,
selection_box = airutils.papi_selection_box,
collision_box = airutils.papi_collision_box,
can_dig = airutils.canDig,
_color = "",
on_destruct = airutils.remove_papi,
on_rightclick=airutils.togglePapiSide,
on_punch = function(pos, node, puncher, pointed_thing)
local player_name = puncher:get_player_name()
local meta = core.get_meta(pos)
if player_name ~= meta:get_string("owner") then
return
end
end,
})
-- PAPI craft
core.register_craft({
output = 'airutils:papi',
recipe = {
{'default:glass', 'default:mese_crystal', 'default:glass'},
{'default:glass', 'default:steel_ingot' , 'default:glass'},
{'' , 'default:steel_ingot' , ''},
}
})

View file

@ -0,0 +1,16 @@
local S = airutils.S
-- trike repair
core.register_craftitem("airutils:repair_tool",{
description = S("Repair Tool"),
inventory_image = "airutils_repair_tool.png",
})
core.register_craft({
output = "airutils:repair_tool",
recipe = {
{"", "default:steel_ingot", ""},
{"", "default:steel_ingot", ""},
{"default:steel_ingot", "", "default:steel_ingot"},
},
})

View file

@ -0,0 +1,105 @@
local S = airutils.S
function airutils.move_target(player, pointed_thing)
local pos = player:get_pos()
local yaw = player:get_look_horizontal()
local object = pointed_thing.ref
--core.chat_send_all(dump(object))
if object then
local obj_pos = object:get_pos()
if not obj_pos then return end
local hip = math.sqrt(math.pow(obj_pos.x - pos.x,2)+math.pow(obj_pos.z - pos.z,2)) + 1
local pos_x = math.sin(yaw) * -hip
local pos_z = math.cos(yaw) * hip
obj_pos.x = pos.x + pos_x
obj_pos.z = pos.z + pos_z
local node = core.get_node(obj_pos).name
local nodedef = core.registered_nodes[node]
local is_airlike = nodedef.drawtype == "airlike"
local is_liquid = (nodedef.drawtype == "flowingliquid" or nodedef.drawtype == "liquid")
if player:get_player_control().sneak == true then
local rotation = object:get_rotation()
if rotation then
rotation.y = yaw + math.rad(180)
object:set_rotation(rotation)
end
else
if is_airlike or is_liquid then object:set_pos(obj_pos) end
end
--[[if object:get_attach() then
local dir = player:get_look_dir()
core.chat_send_all('detach')
object:set_detach()
object:set_rotation(dir)
else
core.chat_send_all('object found')
object:set_attach(player, "", {x=0, y=0, z=20})
end]]--
end
end
core.register_tool("airutils:tug", {
description = S("Tug tool for airport"),
inventory_image = "airutils_tug.png",
stack_max=1,
on_use = function(itemstack, player, pointed_thing)
if not player then
return
end
local is_admin = core.check_player_privs(player, {server=true})
local pos = player:get_pos()
local pname = player:get_player_name()
--[[if areas then
if not areas:canInteract(pos, pname) then
local owners = areas:getNodeOwners(pos)
core.chat_send_player(pname,
S("@1 is protected by @2.",
core.pos_to_string(pos),
table.concat(owners, ", ")))
else
airutils.move_target(player, pointed_thing)
end
end]]--
local is_protected = core.is_protected
if is_protected then
local owner = nil
local object = pointed_thing.ref
if object then
local ent = object:get_luaentity()
if ent then
if ent.owner then owner = ent.owner end
end
end
if not is_protected(pos, pname) or pname == owner or is_admin then
airutils.move_target(player, pointed_thing)
else
core.chat_send_player(pname,
S("@1 is protected.",
core.pos_to_string(pos)))
end
end
if not is_protected then
airutils.move_target(player, pointed_thing)
end
end,
sound = {breaks = "default_tool_breaks"},
})
core.register_craft({
output = "airutils:tug",
recipe = {
{"", "", "default:steel_ingot"},
{"", "default:steel_ingot", ""},
{"default:steel_ingot", "default:stick", "default:diamond"},
}
})

View file

@ -0,0 +1,193 @@
local S = airutils.S
local function check_protection(pos, name)
if core.is_protected(pos, name) then
core.log("action", name
.. " tried to place a Wind Indicator"
.. " at protected position "
.. core.pos_to_string(pos)
)
core.record_protection_violation(pos, name)
return true
end
return false
end
function airutils.WindDplace(player,pos)
if not player then
return
end
local dir = core.dir_to_facedir(vector.new())
local pos1 = vector.new(pos)
local player_name = player:get_player_name()
if check_protection(pos, player_name) then
return
end
core.set_node(pos1, {name="airutils:wind", param2=dir})
local meta = core.get_meta(pos)
meta:set_string("infotext", S("Wind Indicator") .. "\r" .. S("Owned by: @1",player_name))
meta:set_string("owner", player_name)
meta:set_string("dont_destroy", "false")
return true
end
airutils.wind_collision_box = {
type = "fixed",
fixed={{-0.5,0,-0.5,0.5,5.0,0.5},},
}
airutils.wind_selection_box = {
type = "fixed",
fixed={{-0.5,0,-0.5,0.5,5.0,0.5},},
}
local function get_smooth(angle_initial, reference, last_ref, value)
local range = reference-last_ref
local retVal = (value*angle_initial)/range
local retval = angle_initial - retVal
if retval < 0 then retval = 0 end
return retval
end
core.register_entity("airutils:wind_indicator",{
-- common props
physical = true,
stepheight = 0.5,
collide_with_objects = true,
collisionbox = {-0.5, 0, -0.5, 0.5, 5.0, 0.5},
visual = "mesh",
mesh = "airutils_wind.b3d",
textures = {"airutils_red.png", "airutils_black.png", "airutils_white.png", "airutils_metal.png"},
static_save = true,
makes_footstep_sound = false,
_pos = nil,
on_activate = function(self, staticdata, dtime_s)
self._pos = self.object:get_pos()
end,
on_step = function(self,dtime,colinfo)
self.object:set_pos(self._pos)
local wind = airutils.get_wind(self._pos, 1.0)
local wind_yaw = core.dir_to_yaw(wind)
self.object:set_bone_position("ajuste", {x=0,y=42,z=0}, {x=0,y=0,z=90})
self.object:set_bone_position("b_a", {x=0,y=0,z=0}, {x=math.deg(wind_yaw)-90,y=0,z=0})
local false_div = 1 --trying to make it more o minus sensible
local vel = ((vector.dot(vector.multiply(wind,dtime),wind))/false_div)*100
--core.chat_send_all(vel)
local b_b = 65
if vel > 11 then
b_b = get_smooth(65, 11, 0, vel)
end
self.object:set_bone_position("b_b", {x=0,y=8.25,z=0}, {x=0,y=0,z=-b_b})
local b_c = 15
if vel > 16 then
b_c = get_smooth(15, 16, 11, vel)
end
self.object:set_bone_position("b_c", {x=0,y=6.0,z=0}, {x=0,y=0,z=-b_c})
local b_d = 5
if vel > 22 then
b_d = get_smooth(5, 22, 16, vel)
end
self.object:set_bone_position("b_d", {x=0,y=4.5,z=0}, {x=0,y=0,z=-b_d})
local b_e = 2
if vel > 28 then
b_e = get_smooth(2, 28, 22, vel)
end
self.object:set_bone_position("b_e", {x=0,y=3,z=0}, {x=0,y=0,z=-b_e})
--core.chat_send_all("Wind Direction: "..math.deg(wind_yaw))
end, -- required
--on_activate = mobkit.actfunc, -- required
--get_staticdata = mobkit.statfunc,
max_hp = 65535,
timeout = 0,
on_punch=function(self, puncher)
return
end,
on_rightclick = function(self, clicker)
local wind = airutils.get_wind(self.object:get_pos(), 2.0)
local wind_yaw = core.dir_to_yaw(wind)
core.chat_send_player(clicker:get_player_name(),core.colorize('#00ff00', S(" >>> The wind direction now is @1", math.deg(wind_yaw))))
return
end,
})
-- Wind Indicator node (default left)
core.register_node("airutils:wind",{
description = S("Wind Direction Indicator"),
waving = 1,
tiles = {"default_steel_block.png","default_steel_block.png","default_steel_block.png","default_steel_block.png","default_steel_block.png","default_steel_block.png"},
paramtype = "light",
paramtype2 = "leveled",
is_ground_content = false,
groups = {cracky = 1, level = 2},
walkable = true,
selection_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
{-0.1, 0.5, -0.1, 0.1, 2.0, 0.1}
}
},
node_dig_prediction = "default:dirt",
node_placement_prediction = "airutils:wind",
on_place = function(itemstack, placer, pointed_thing)
local pos = pointed_thing.above
local player_name = placer:get_player_name()
if not core.is_protected(pos, player_name) and not core.is_protected(pos, player_name) then
core.set_node(pos, {name = "airutils:wind",param2 = 1 })
core.add_entity({x=pos.x, y=pos.y, z=pos.z},"airutils:wind_indicator")
if not (creative and creative.is_enabled_for and creative.is_enabled_for(player_name)) then
itemstack:take_item()
end
else
core.chat_send_player(player_name, S("Node is protected"))
core.record_protection_violation(pos, player_name)
end
return itemstack
end,
on_destruct = function(pos)
local meta=core.get_meta(pos)
if meta then
local cpos = {x=pos.x, y= pos.y, z=pos.z}
local object = core.get_objects_inside_radius(cpos, 1)
for _,obj in ipairs(object) do
local entity = obj:get_luaentity()
if entity and entity.name == "airutils:wind_indicator" then
obj:remove()
end
end
end
end,
})
-- WIND craft
core.register_craft({
output = 'airutils:wind',
recipe = {
{'wool:white', 'wool:white', 'wool:white'},
{'wool:white', 'default:steel_ingot' , 'wool:white'},
{'' , 'default:steel_ingot' , ''},
}
})

View file

@ -0,0 +1,197 @@
local S = airutils.S
local function attach_entity(self, target_obj, ent, dest_pos, relative_pos, attach_up)
attach_up = attach_up or false
if not target_obj then return end
if self.object then
if self._vehicle_custom_data then
local y = 0
if attach_up == false then
y = self.initial_properties.collisionbox[2] - ent.initial_properties.collisionbox[2]
else
y = (relative_pos.y/10) + ent.initial_properties.collisionbox[5]
end
dest_pos.y = dest_pos.y + y
target_obj:set_pos(dest_pos)
local ent = target_obj:get_luaentity()
if ent then
relative_pos.y = y*10
target_obj:set_attach(self.object,'',relative_pos,{x=0,y=0,z=0})
self._vehicle_custom_data.simple_external_attach_entity = ent.name
self._vehicle_custom_data.simple_external_attach_pos = relative_pos
self._vehicle_custom_data.simple_external_attach_invid = ent._inv_id --why?! Because I can identify the target entity by it's inventory ;)
end
end
end
end
function airutils.get_attached_entity(self)
if not self._vehicle_custom_data then return nil, nil end
if not self._vehicle_custom_data.simple_external_attach_entity then return nil, nil end
local inv_id = self._vehicle_custom_data.simple_external_attach_invid
local pos = self.object:get_pos()
local nearby_objects = minetest.get_objects_inside_radius(pos, 32)
for i,obj in ipairs(nearby_objects) do
local ent = obj:get_luaentity()
if ent then
if ent._inv_id then
if ent._inv_id == inv_id then
return ent, obj
end
end
end
end
return nil, nil
end
function airutils.dettach_entity(self)
local ent, obj = airutils.get_attached_entity(self)
if ent and obj then
local relative_pos = self._vehicle_custom_data.simple_external_attach_pos
local pos = self.object:get_pos()
local rotation = self.object:get_rotation()
local direction = rotation.y
local velocity = self.object:get_velocity()
local move = -1*relative_pos.z/10
pos.x = pos.x + move * math.sin(direction)
pos.z = pos.z - move * math.cos(direction)
pos.y = pos.y + self.initial_properties.collisionbox[2] - ent.initial_properties.collisionbox[2]
obj:set_detach()
obj:set_pos(pos)
obj:set_rotation(rotation)
obj:set_velocity(velocity)
--clear
self._vehicle_custom_data.simple_external_attach_entity = nil
self._vehicle_custom_data.simple_external_attach_pos = nil
self._vehicle_custom_data.simple_external_attach_invid = nil
end
end
function airutils.attach_external_object(self, object, ent, destination_pos, relative_pos, attach_up)
local dest_pos = vector.new(destination_pos)
local rel_pos = vector.new(relative_pos)
if attach_up == false then
rel_pos.y = 0
end
dest_pos = vector.add(dest_pos, vector.divide(rel_pos,10))
attach_entity(self, object, ent, dest_pos, rel_pos, attach_up)
end
function airutils.simple_external_attach(self, relative_pos, entity_name, radius, attach_up)
attach_up = attach_up or false
radius = radius or 12
if self.object then
local curr_ent, _ = airutils.get_attached_entity(self)
if curr_ent then return end
local pos = self.object:get_pos()
local nearby_objects = minetest.get_objects_inside_radius(pos, radius)
for i,obj in ipairs(nearby_objects) do
if obj == self.object then
table.remove(nearby_objects,i)
end
local ent = obj:get_luaentity()
if ent then
if ent.name == entity_name then
airutils.attach_external_object(self, nearby_objects[i], ent, pos, relative_pos, attach_up)
return
end
end
end
end
end
--execute on load
function airutils.restore_external_attach(self)
if not self._vehicle_custom_data then return end
if not self._vehicle_custom_data.simple_external_attach_invid then return end
local pos = self.object:get_pos()
local dest_pos = vector.new(pos)
local relative_pos = self._vehicle_custom_data.simple_external_attach_pos
local inv_id = self._vehicle_custom_data.simple_external_attach_invid
dest_pos = vector.add(dest_pos, relative_pos)
minetest.after(0.3, function()
local nearby_objects = minetest.get_objects_inside_radius(pos, 32)
local ent
for i,obj in ipairs(nearby_objects) do
ent = obj:get_luaentity()
if ent then
--minetest.chat_send_all(dump(ent.name))
if ent._inv_id then
--minetest.chat_send_all(">> "..dump(ent._inv_id).." >> "..dump(inv_id))
if ent._inv_id == inv_id and ent._inv_id ~= self._inv_id then
--minetest.chat_send_all("++ "..dump(ent._inv_id).." ++ "..dump(inv_id))
local target_obj = nearby_objects[i]
target_obj:set_pos(dest_pos)
target_obj:set_attach(self.object,'',relative_pos,{x=0,y=0,z=0})
--attach_entity(self, nearby_objects[i], dest_pos, relative_pos, entity_name, inv_id)
return
end
end
end
end
end)
--clear
--self._vehicle_custom_data.simple_external_attach_entity = nil
--self._vehicle_custom_data.simple_external_attach_pos = nil
--self._vehicle_custom_data.simple_external_attach_invid = nil
end
minetest.register_chatcommand("remove_hook", {
params = "",
description = S("Dettach current vehicle from another"),
privs = {interact=true},
func = function(name, param)
local colorstring = core.colorize('#ff0000', S(" >>> you are not inside a plane"))
local player = minetest.get_player_by_name(name)
local attached_to = player:get_attach()
if attached_to ~= nil then
local seat = attached_to:get_attach()
if seat ~= nil then
local entity = seat:get_luaentity()
if entity then
if entity.on_step == airutils.on_step then
local rem_obj = entity.object:get_attach()
if not rem_obj then
minetest.chat_send_player(name,core.colorize('#ff0000', S(" >>> no hook found")))
return
end
local rem_ent = rem_obj:get_luaentity()
local pos = rem_ent.object:get_pos()
local rotation = rem_ent.object:get_rotation()
local direction = rotation.y
local velocity = rem_ent.object:get_velocity()
local move = 0
if rem_ent._vehicle_custom_data.simple_external_attach_pos then
move = -1*rem_ent._vehicle_custom_data.simple_external_attach_pos.z/10
end
pos.x = pos.x + move * math.sin(direction)
pos.z = pos.z + move * math.cos(direction)
pos.y = pos.y + rem_ent.initial_properties.collisionbox[2] - entity.initial_properties.collisionbox[2]
entity.object:set_detach()
entity.object:set_pos(pos)
entity.object:set_rotation(rotation)
entity.object:set_velocity(velocity)
--clear
rem_ent._vehicle_custom_data.simple_external_attach_entity = nil
rem_ent._vehicle_custom_data.simple_external_attach_pos = nil
rem_ent._vehicle_custom_data.simple_external_attach_invid = nil
else
minetest.chat_send_player(name,colorstring)
end
end
end
else
minetest.chat_send_player(name,colorstring)
end
end
})

View file

@ -0,0 +1,24 @@
--
-- seat pivot
--
minetest.register_entity('airutils:seat_base',{
initial_properties = {
physical = false,
collide_with_objects=false,
pointable=false,
visual = "mesh",
mesh = "airutils_seat_base.b3d",
textures = {"airutils_alpha.png",},
},
on_activate = function(self,std)
self.sdata = minetest.deserialize(std) or {}
if self.sdata.remove then self.object:remove() end
end,
get_staticdata=function(self)
self.sdata.remove=true
return minetest.serialize(self.sdata)
end,
})

View file

@ -0,0 +1 @@
Airport Utils for Minetest

676
mods/airutils/init.lua Normal file
View file

@ -0,0 +1,676 @@
-- Minetest 5.4.1 : airutils
airutils = {}
airutils.storage = core.get_mod_storage()
local storage = airutils.storage
airutils.colors ={
black='#2b2b2b',
blue='#0063b0',
brown='#8c5922',
cyan='#07B6BC',
dark_green='#567a42',
dark_grey='#6d6d6d',
green='#4ee34c',
grey='#9f9f9f',
magenta='#ff0098',
orange='#ff8b0e',
pink='#ff62c6',
red='#dc1818',
violet='#a437ff',
white='#FFFFFF',
yellow='#ffe400',
}
airutils.S = nil
if(core.get_translator ~= nil) then
airutils.S = core.get_translator(core.get_current_modname())
else
airutils.S = function ( s ) return s end
end
local S = airutils.S
local load_blast_damage = storage:get_int("blast_damage")
airutils.blast_damage = true
-- 1 == true ---- 2 == false
if load_blast_damage == 2 then airutils.blast_damage = false end
airutils.is_minetest = core.get_modpath("player_api")
airutils.is_mcl = core.get_modpath("mcl_player")
airutils.is_repixture = core.get_modpath("rp_player")
airutils.fuel = {['biofuel:biofuel'] = 1,['biofuel:bottle_fuel'] = 1,
['biofuel:phial_fuel'] = 0.25, ['biofuel:fuel_can'] = 10,
['airutils:biofuel'] = 1,}
airutils.protect_in_areas = core.settings:get_bool('airutils_protect_in_areas')
airutils.debug_log = core.settings:get_bool('airutils_debug_log')
if not core.settings:get_bool('airutils_disable_papi') then
dofile(core.get_modpath("airutils") .. DIR_DELIM .. "airutils_papi.lua")
end
if not core.settings:get_bool('airutils_disable_tug') then
dofile(core.get_modpath("airutils") .. DIR_DELIM .. "airutils_tug.lua")
end
if not core.settings:get_bool('airutils_disable_repair') then
dofile(core.get_modpath("airutils") .. DIR_DELIM .. "airutils_repair.lua")
end
airutils.splash_texture = "airutils_splash.png"
airutils.use_water_particles = false
if core.settings:get_bool('airutils_enable_water_particles', false) then
airutils.use_water_particles = true
end
airutils._use_signs_api = true
if not core.get_modpath("signs_lib") then airutils._use_signs_api = false end
if core.settings:get_bool('airutils_disable_signs_api') then airutils._use_signs_api = false end
airutils.get_wind = dofile(core.get_modpath("airutils") .. DIR_DELIM ..'/wind.lua')
dofile(core.get_modpath("airutils") .. DIR_DELIM .. "uuid_manager.lua")
dofile(core.get_modpath("airutils") .. DIR_DELIM .. "common_entities.lua")
dofile(core.get_modpath("airutils") .. DIR_DELIM .. "airutils_wind.lua")
dofile(core.get_modpath("airutils") .. DIR_DELIM .. "water_splash.lua")
dofile(core.get_modpath("airutils") .. DIR_DELIM .. "inventory_management.lua")
dofile(core.get_modpath("airutils") .. DIR_DELIM .. "light.lua")
dofile(core.get_modpath("airutils") .. DIR_DELIM .. "physics_lib.lua")
dofile(core.get_modpath("airutils") .. DIR_DELIM .. "lib_planes" .. DIR_DELIM .. "init.lua")
dofile(core.get_modpath("airutils") .. DIR_DELIM .. "lib_copter" .. DIR_DELIM .. "init.lua")
dofile(core.get_modpath("airutils") .. DIR_DELIM .. "texture_management.lua")
dofile(core.get_modpath("airutils") .. DIR_DELIM .. "attach_extern_ent.lua")
if airutils._use_signs_api then dofile(core.get_modpath("airutils") .. DIR_DELIM .. "text.lua") end
local is_biofuel_installed = false
if biomass then
if biomass.convertible_groups then is_biofuel_installed = true end
end
local enable_internal_biofuel = core.settings:get_bool('airutils.force_enable_biofuel')
if not is_biofuel_installed or enable_internal_biofuel then
dofile(core.get_modpath("airutils") .. DIR_DELIM .. "airutils_biofuel.lua")
end
if core.get_modpath("player_api") and not core.settings:get_bool('airutils.disable_uniforms') then
dofile(core.get_modpath("airutils") .. DIR_DELIM .. "pilot_skin_manager.lua")
end
function airutils.remove(pos)
local meta = core.get_meta(pos)
if meta:get_string("dont_destroy") == "true" then
-- when swapping it
return
end
end
function airutils.canDig(pos, player)
local meta = core.get_meta(pos)
return meta:get_string("dont_destroy") ~= "true"
and player:get_player_name() == meta:get_string("owner")
end
function airutils.check_node_below(obj, how_low)
local pos_below = obj:get_pos()
if pos_below then
pos_below.y = pos_below.y - how_low
local node_below = core.get_node(pos_below).name
local nodedef = core.registered_nodes[node_below]
local touching_ground = not nodedef or -- unknown nodes are solid
nodedef.walkable or false
local liquid_below = not touching_ground and nodedef.liquidtype ~= "none"
return touching_ground, liquid_below
end
return nil, nil
end
function airutils.check_is_under_water(obj)
local pos_up = obj:get_pos()
pos_up.y = pos_up.y + 0.1
local node_up = core.get_node(pos_up).name
local nodedef = core.registered_nodes[node_up]
local liquid_up = nodedef.liquidtype ~= "none"
return liquid_up
end
function airutils.setText(self, vehicle_name)
local properties = self.object:get_properties()
local formatted = ""
if type(self.hp_max) ~= "number" then self.hp_max = 0.1 end --strange error when hpmax is NaN
if self.hp_max then
formatted = S(" Current hp: ") .. string.format(
"%.2f", self.hp_max
)
end
if properties then
properties.infotext = S("Nice @1 of @2.@3", vehicle_name, self.owner, formatted)
self.object:set_properties(properties)
end
end
function airutils.transfer_control(self, status)
if not self._have_copilot then return end
if status == false then
self._command_is_given = false
if self.co_pilot then
core.chat_send_player(self.co_pilot,
core.colorize('#ff0000', S(" >>> The captain got the control.")))
end
if self.driver_name then
core.chat_send_player(self.driver_name,
core.colorize('#00ff00', S(" >>> The control is with you now.")))
end
else
self._command_is_given = true
if self.co_pilot then
core.chat_send_player(self.co_pilot,
core.colorize('#00ff00', S(" >>> The control is with you now.")))
end
if self.driver_name then core.chat_send_player(self.driver_name,S(" >>> The control was given.")) end
end
end
--returns 0 for old, 1 for new
function airutils.detect_player_api(player)
local player_proterties = player:get_properties()
--local mesh = "character.b3d"
--if player_proterties.mesh == mesh then
if core.get_modpath("player_api") then
local models = player_api.registered_models
local character = models[player_proterties.mesh]
--core.chat_send_all(dump(character));
if character then
if character.animations.sit.eye_height then
--core.chat_send_all(dump(character.animations.sit.eye_height));
if character.animations.sit.eye_height == 0.8 then
--core.chat_send_all("new model");
return 1
else
--core.chat_send_all("new height");
return 2 --strange bug with armor ands skins returning 1.47
end
else
--core.chat_send_all("old model");
return 0
end
end
end
return 0
end
local function get_nodedef_field(nodename, fieldname)
if not core.registered_nodes[nodename] then
return nil
end
return core.registered_nodes[nodename][fieldname]
end
--for
function airutils.eval_vertical_interception(initial_pos, end_pos)
local ret_y = nil
local cast = core.raycast(initial_pos, end_pos, true, true)
local thing = cast:next()
while thing do
if thing.type == "node" then
local pos = thing.intersection_point
if pos then
local nodename = core.get_node(thing.under).name
local drawtype = get_nodedef_field(nodename, "drawtype")
if drawtype ~= "plantlike" then
ret_y = pos.y
break
end
end
end
thing = cast:next()
end
return ret_y
end
--lift
local function pitchroll2pitchyaw(aoa,roll)
if roll == 0.0 then return aoa,0 end
-- assumed vector x=0,y=0,z=1
local p1 = math.tan(aoa)
local y = math.cos(roll)*p1
local x = math.sqrt(p1^2-y^2)
local pitch = math.atan(y)
local yaw=math.atan(x)*math.sign(roll)
return pitch,yaw
end
local function lerp(a, b, c)
return a + (b - a) * c
end
function airutils.quadBezier(t, p0, p1, p2)
local l1 = lerp(p0, p1, t)
local l2 = lerp(p1, p2, t)
local quad = lerp(l1, l2, t)
return quad
end
function airutils.get_ground_effect_lift(self, curr_pos, lift, wingspan)
local half_wingspan = wingspan/2
local lower_collision = self.initial_properties.collisionbox[2]
if not self._ground_effect_ammount_percent then self._ground_effect_ammount_percent = 0.5 end
local initial_pos = {x=curr_pos.x, y=curr_pos.y + lower_collision, z=curr_pos.z} --lets make my own table to avoid interferences
if self._extra_lift == nil then self._extra_lift = 0 end
if self._last_ground_effect_eval == nil then self._last_ground_effect_eval = 0 end
self._last_ground_effect_eval = self._last_ground_effect_eval + self.dtime --dtime cames from airutils
local ground_distance = wingspan
if self._last_ground_effect_eval >= 0.25 then
self._last_ground_effect_eval = 0
self._last_ground_distance = ground_distance
local ground_y = airutils.eval_vertical_interception(initial_pos, {x=initial_pos.x, y=initial_pos.y - half_wingspan, z=initial_pos.z})
if ground_y then
ground_distance = initial_pos.y - ground_y
end
--core.chat_send_all(dump(ground_distance))
--smooth the curve
local distance_factor = ((ground_distance) * 1) / (wingspan)
local effect_factor = airutils.quadBezier(distance_factor, 0, wingspan, 0)
if effect_factor < 0 then effect_factor = 0 end
if effect_factor > 0 then
effect_factor = math.abs( half_wingspan - effect_factor )
end
local lift_factor = ((effect_factor) * 1) / (half_wingspan) --agora isso é um percentual
local max_extra_lift_percent = self._ground_effect_ammount_percent * lift --e aqui o maximo extra de sustentação
local extra_lift = max_extra_lift_percent * lift_factor
self._extra_lift = extra_lift
end
return self._extra_lift --return the value stored
end
-- velocity: velocity table
-- accel: current acceleration
-- longit_speed: the vehicle speed
-- roll: roll angle
-- curr_pos: current position
-- lift: lift factor (very simplified)
-- max_height: the max ceilling for the airplane
-- wingspan: for ground effect calculation
function airutils.getLiftAccel(self, velocity, accel, longit_speed, roll, curr_pos, in_lift, max_height, wingspan)
if longit_speed == nil then longit_speed = 0 end
wingspan = wingspan or 10
local lift = in_lift
if not airutils.ground_effect_is_disabled then
local ground_effect_extra_lift = airutils.get_ground_effect_lift(self, curr_pos, in_lift, wingspan)
lift = lift + ground_effect_extra_lift
end
--lift calculations
-----------------------------------------------------------
max_height = max_height or 20000
local wing_config = 0
if self._wing_configuration then wing_config = self._wing_configuration end --flaps!
local retval = accel
local min_speed = 1;
if self._min_speed then min_speed = self._min_speed end
min_speed = min_speed / 2
local striped_velocity = vector.new(velocity)
local cut_velocity = (min_speed * 1)/longit_speed
striped_velocity.x = striped_velocity.x - (striped_velocity.x * cut_velocity)
striped_velocity.z = striped_velocity.z - (striped_velocity.z * cut_velocity)
local angle_of_attack = math.rad(self._angle_of_attack + wing_config)
--local acc = 0.8
local daoa = math.deg(angle_of_attack)
--core.chat_send_all(dump(daoa))
--to decrease the lift coefficient at hight altitudes
local curr_percent_height = (100 - ((curr_pos.y * 100) / max_height))/100
local rotation=self.object:get_rotation()
local vrot = airutils.dir_to_rot(velocity,rotation)
local hpitch,hyaw = pitchroll2pitchyaw(angle_of_attack,roll)
local hrot = {x=vrot.x+hpitch,y=vrot.y-hyaw,z=roll}
local hdir = airutils.rot_to_dir(hrot) --(hrot)
local cross = vector.cross(velocity,hdir)
local lift_dir = vector.normalize(vector.cross(cross,hdir))
local lift_coefficient = (0.24*math.abs(daoa)*(1/(0.025*daoa+3))^4*math.sign(daoa))
local lift_val = math.abs((lift*(vector.length(striped_velocity)^2)*lift_coefficient)*curr_percent_height)
if lift_val < 1 then lift_val = 1 end -- hipotetical aerodinamic wing will have no "lift" for down
if self._climb_speed then --for helicopters
if (velocity.y) > self._climb_speed then lift_val = math.abs(airutils.gravity) end
end
if self._lift_dead_zone then
if lift_val < (math.abs(airutils.gravity)+self._lift_dead_zone) and lift_val > (math.abs(airutils.gravity)-self._lift_dead_zone) then
lift_val = math.abs(airutils.gravity)
end
end
if airutils.show_lift then
core.chat_send_player(airutils.show_lift,core.colorize('#ffff00', " >>> lift: "..lift_val))
end
local lift_acc = vector.multiply(lift_dir,lift_val)
--lift_acc=vector.add(vector.multiply(core.yaw_to_dir(rotation.y),acc),lift_acc)
retval = vector.add(retval,lift_acc)
-----------------------------------------------------------
-- end lift
return retval
end
function airutils.get_plane_pitch(y_velocity, longit_speed, min_speed, angle_of_attack)
local v_speed_factor = 0
if longit_speed > 0 then v_speed_factor = (y_velocity * math.rad(2)) end --the pitch for climbing or descenting
local min_rotation_speed = min_speed/2
local pitch_by_longit_speed = 0
if longit_speed > min_rotation_speed then --just start the rotation after the rotation speed
local scale_pitch_graph = ((longit_speed-min_rotation_speed)*1)/min_rotation_speed --lets use the min rotation speed for reference to when we will start the control work
if scale_pitch_graph > 1 then scale_pitch_graph = 1 end --normalize to 100%
pitch_by_longit_speed = airutils.quadBezier(scale_pitch_graph, 0, angle_of_attack, angle_of_attack) --here the magic happens using a bezier curve
end
return math.rad(pitch_by_longit_speed) + v_speed_factor
end
function airutils.adjust_attack_angle_by_speed(angle_of_attack, min_angle, max_angle, limit, longit_speed, ideal_step, dtime)
--coloca em nivel gradualmente
local factor = 0
if angle_of_attack > max_angle then factor = -1 end
if angle_of_attack < min_angle then factor = 1 end
local correction = (limit*(longit_speed/5000)) * factor * (dtime/ideal_step)
--core.chat_send_all("angle: "..angle_of_attack.." - correction: "..correction)
local new_angle_of_attack = angle_of_attack + correction
return new_angle_of_attack
end
function airutils.elevator_auto_correction(self, longit_speed, dtime, max_speed, elevator_angle, elevator_limit, ideal_step, intensity)
intensity = intensity or 500
if longit_speed <= 0 then return end
local factor = 1
if self._elevator_angle > 0 then factor = -1 end
local ref_speed = longit_speed
if ref_speed > max_speed then ref_speed = max_speed end
local speed_scale = (elevator_limit + (elevator_limit/10)) - ((elevator_limit*ref_speed)/max_speed)
local divisor = intensity
speed_scale = speed_scale / divisor
local correction = speed_scale * factor * (dtime/ideal_step)
local before_correction = elevator_angle
local new_elevator_angle = elevator_angle + correction
if math.sign(before_correction) ~= math.sign(new_elevator_angle) then
new_elevator_angle = 0
end
return new_elevator_angle
end
function airutils.set_paint(self, puncher, itmstck, texture_name)
local item_name = ""
if itmstck then item_name = itmstck:get_name() end
if item_name == "automobiles_lib:painter" or item_name == "bike:painter" then
--painting with bike painter
local meta = itmstck:get_meta()
local colstr = meta:get_string("paint_color")
--core.chat_send_all(dump(colstr))
airutils.paint(self, colstr, texture_name)
return true
else
--painting with dyes
local split = string.split(item_name, ":")
local indx, _
if split[1] then _,indx = split[1]:find('dye') end
if indx then
--[[for clr,_ in pairs(airutils.colors) do
local _,x = split[2]:find(clr)
if x then color = clr end
end]]--
--lets paint!!!!
local color = (item_name:sub(indx+1)):gsub(":", "")
local colstr = airutils.colors[color]
--core.chat_send_all(color ..' '.. dump(colstr))
if colstr then
airutils.paint(self, colstr, texture_name)
if self._alternate_painting_texture and self._mask_painting_texture then
airutils.paint_with_mask(self, colstr, self._alternate_painting_texture, self._mask_painting_texture)
end
itmstck:set_count(itmstck:get_count()-1)
if puncher ~= nil then puncher:set_wielded_item(itmstck) end
return true
end
-- end painting
end
end
return false
end
function airutils._set_name(self)
if not airutils._use_signs_api then return end
local l_textures = self.object:get_properties().textures --self.initial_properties.textures
for _, texture in ipairs(l_textures) do
local indx = texture:find('airutils_name_canvas.png')
if indx then
l_textures[_] = "airutils_name_canvas.png^"..airutils.convert_text_to_texture(self._ship_name, self._name_color or 0, self._name_hor_aligment or 0.8)
end
end
self.object:set_properties({textures=l_textures})
end
--painting
function airutils.paint(self, colstr, texture_name)
if not self then return end
if colstr then
self._color = colstr
local l_textures = self.initial_properties.textures
for _, texture in ipairs(l_textures) do
local indx = texture:find(texture_name)
if indx then
l_textures[_] = texture_name.."^[multiply:".. colstr
end
end
self.object:set_properties({textures=l_textures})
end
end
function airutils.getAngleFromPositions(origin, destiny)
local angle_north = math.deg(math.atan2(destiny.x - origin.x, destiny.z - origin.z))
if angle_north < 0 then angle_north = angle_north + 360 end
return angle_north
end
function airutils.sit(player)
--set_animation(frame_range, frame_speed, frame_blend, frame_loop)
player:set_animation({x = 81, y = 160},30, 0, true)
if core.get_modpath("emote") then emote.start(player:get_player_name(), "sit") end
end
local function get_norm_angle(angle)
local new_angle = angle/360
new_angle = (new_angle - math.floor(new_angle))*360
if new_angle < -180 then new_angle = new_angle + 360 end
if new_angle > 180 then new_angle = new_angle - 360 end
return new_angle
end
function airutils.normalize_rotations(rotations)
return {x = get_norm_angle(rotations.x), y = get_norm_angle(rotations.y), z = get_norm_angle(rotations.z)}
end
core.register_chatcommand("enable_blast_damage", {
params = "<true/false>",
description = S("Enable/disable explosion blast damage"),
privs = {server=true},
func = function(name, param)
local command = param
if command == "false" then
airutils.blast_damage = false
core.chat_send_player(name, S(">>> Blast damage by explosion is disabled"))
else
airutils.blast_damage = true
core.chat_send_player(name, S(">>> Blast damage by explosion is enabled"))
end
local save = 2
if airutils.blast_damage == true then save = 1 end
storage:set_int("blast_damage", save)
end,
})
core.register_chatcommand("transfer_ownership", {
params = "<new_owner>",
description = S("Transfer the property of a plane to another player"),
privs = {interact=true},
func = function(name, param)
local player = core.get_player_by_name(name)
local target_player = core.get_player_by_name(param)
local attached_to = player:get_attach()
if attached_to ~= nil then
if target_player ~= nil then
local seat = attached_to:get_attach()
if seat ~= nil then
local entity = seat:get_luaentity()
if entity then
if entity.owner == name or core.check_player_privs(name, {protection_bypass=true}) then
entity.owner = param
core.chat_send_player(name,core.colorize('#00ff00', S(" >>> This plane now is property of: ")..param))
else
core.chat_send_player(name,core.colorize('#ff0000', S(" >>> only the owner or moderators can transfer this airplane")))
end
end
end
else
core.chat_send_player(name,core.colorize('#ff0000', S(" >>> the target player must be logged in")))
end
else
core.chat_send_player(name,core.colorize('#ff0000', S(" >>> you are not inside a plane to perform the command")))
end
end
})
core.register_chatcommand("eject_from_plane", {
params = "",
description = S("Ejects from a plane"),
privs = {interact = true},
func = function(name, param)
local colorstring = core.colorize('#ff0000', S(" >>> you are not inside a plane"))
local player = core.get_player_by_name(name)
local attached_to = player:get_attach()
if attached_to ~= nil then
local seat = attached_to:get_attach()
if seat ~= nil then
local entity = seat:get_luaentity()
if entity then
if entity.on_step == airutils.on_step then
if entity.driver_name == name then
airutils.dettachPlayer(entity, player)
elseif entity._passenger == name then
local passenger = core.get_player_by_name(entity._passenger)
airutils.dettach_pax(entity, passenger)
end
else
core.chat_send_player(name,colorstring)
end
end
end
else
core.chat_send_player(name,colorstring)
end
end
})
core.register_chatcommand("ground_effect", {
params = "<on/off>",
description = S("Enables/disables the ground effect (for debug purposes)"),
privs = {server=true},
func = function(name, param)
if core.check_player_privs(name, {server=true}) then
if param == "on" or param == "" then
airutils.ground_effect_is_disabled = nil
core.chat_send_player(name,core.colorize('#00ff00', S(" >>> Ground effect was turned on.")))
elseif param == "off" then
airutils.ground_effect_is_disabled = true
core.chat_send_player(name,core.colorize('#0000ff', S(">>> Ground effect was turned off.")))
end
else
core.chat_send_player(name,core.colorize('#ff0000', S(" >>> You need 'server' priv to run this command.")))
end
end
})
core.register_chatcommand("show_lift", {
params = "<on/off>",
description = S("Enables/disables the lift printing (for debug purposes)"),
privs = {server=true},
func = function(name, param)
if core.check_player_privs(name, {server=true}) then
if param == "on" or param == "" then
airutils.show_lift = name
core.chat_send_player(name,core.colorize('#0000ff', S(" >>> Lift printing turned on.")))
elseif param == "off" then
airutils.show_lift = nil
core.chat_send_player(name,core.colorize('#00ff00', S(" >>> Lift printing turned off.")))
end
else
core.chat_send_player(name,core.colorize('#ff0000', S(" >>> You need 'server' priv to run this command.")))
end
end
})
if airutils._use_signs_api then
local function prefix_change(name, param)
local colorstring = core.colorize('#ff0000', S(" >>> you are not inside a vehicle"))
local player = core.get_player_by_name(name)
if not player then return end
local attached_to = player:get_attach()
if attached_to ~= nil then
local seat = attached_to:get_attach()
if seat ~= nil then
local entity = seat:get_luaentity()
if entity then
if entity.owner == name or core.check_player_privs(name, {protection_bypass=true}) then
if param then
entity._ship_name = string.sub(param, 1, 40)
else
entity._ship_name = ""
end
airutils._set_name(entity)
core.chat_send_player(name,core.colorize('#00ff00', S(" >>> the vehicle name was changed")))
else
core.chat_send_player(name,core.colorize('#ff0000', S(" >>> only the owner or moderators can name this vehicle")))
end
end
end
else
core.chat_send_player(name,colorstring)
end
end
core.register_chatcommand("set_vehicle_name", {
params = "<name>",
description = S("this command is an alias for /set_prefix"),
privs = {interact = true},
func = prefix_change,
})
core.register_chatcommand("set_prefix", {
params = "<name>",
description = S("Sets the vehicle prefix"),
privs = {interact = true},
func = prefix_change,
})
end

View file

@ -0,0 +1,217 @@
local storage = airutils.storage
airutils.modname = core.get_current_modname()
--function to format formspec for mineclone. In case of minetest, just returns an empty string
function airutils.get_itemslot_bg(a, b, c, d)
if airutils.is_mcl then
if mcl_formspec then
return mcl_formspec.get_itemslot_bg(a,b,c,d)
end
end
return ""
end
local function get_formspec_by_size(self, size)
local background = ""
local hotbar = ""
local is_minetest_game = airutils.is_minetest or false
if is_minetest_game then
background = background .. default.gui_bg .. default.gui_bg_img .. default.gui_slots
hotbar = default.get_hotbar_bg(0,4.85)
end
local default_inventory_formspecs = {
["2"]="size[8,6]".. background ..
"list[detached:" .. self._inv_id .. ";main;3.0,0;3,1;]" .. airutils.get_itemslot_bg(3.0, 0, 2, 1) ..
"list[current_player;main;0,2;8,4;]" .. airutils.get_itemslot_bg(0, 2, 8, 4) ..
"listring[]",
["3"]="size[8,6]".. background ..
"list[detached:" .. self._inv_id .. ";main;2.5,0;3,1;]" .. airutils.get_itemslot_bg(2.5, 0, 3, 1) ..
"list[current_player;main;0,2;8,4;]" .. airutils.get_itemslot_bg(0, 2, 8, 4) ..
"listring[]",
["4"]="size[8,6]".. background ..
"list[detached:" .. self._inv_id .. ";main;2,0;4,1;]" .. airutils.get_itemslot_bg(2.0, 0, 4, 1) ..
"list[current_player;main;0,2;8,4;]" .. airutils.get_itemslot_bg(0, 2, 8, 4) ..
"listring[]",
["6"]="size[8,6]".. background ..
"list[detached:" .. self._inv_id .. ";main;1,0;6,1;]".. airutils.get_itemslot_bg(1.0, 0, 6, 1) ..
"list[current_player;main;0,2;8,4;]" .. airutils.get_itemslot_bg(0, 2, 8, 4) ..
"listring[]",
["8"]="size[8,6]".. background ..
"list[detached:" .. self._inv_id .. ";main;0,0;8,1;]".. airutils.get_itemslot_bg(0, 0, 8, 1) ..
"list[current_player;main;0,2;8,4;]" .. airutils.get_itemslot_bg(0, 2, 8, 4) ..
"listring[]",
["12"]="size[8,7]".. background ..
"list[detached:" .. self._inv_id .. ";main;1,0;6,2;]".. airutils.get_itemslot_bg(1, 0, 6, 2) ..
"list[current_player;main;0,3;8,4;]" .. airutils.get_itemslot_bg(0, 3, 8, 4) ..
"listring[]",
["16"]="size[8,7]".. background ..
"list[detached:" .. self._inv_id .. ";main;0,0;8,2;]".. airutils.get_itemslot_bg(0, 0, 8, 2) ..
"list[current_player;main;0,3;8,4;]" .. airutils.get_itemslot_bg(0, 3, 8, 4) ..
"listring[]",
["24"]="size[8,8]".. background ..
"list[detached:" .. self._inv_id .. ";main;0,0;8,3;]".. airutils.get_itemslot_bg(0, 0, 8, 3) ..
"list[current_player;main;0,4;8,4;]" .. airutils.get_itemslot_bg(0, 4, 8, 4) ..
"listring[]",
["32"]="size[8,9]".. background ..
"list[detached:" .. self._inv_id .. ";main;0,0.3;8,4;]".. airutils.get_itemslot_bg(0, 0.3, 8, 4) ..
"list[current_player;main;0,5;8,4;]".. airutils.get_itemslot_bg(0, 5, 8, 4) ..
"listring[]" ..
hotbar,
["50"]="size[10,10]".. background ..
"list[detached:" .. self._inv_id .. ";main;0,0;10,5;]".. airutils.get_itemslot_bg(0, 0, 10, 5) ..
"list[current_player;main;1,6;8,4;]" .. airutils.get_itemslot_bg(1, 6, 8, 4) ..
"listring[]",
}
local formspec = default_inventory_formspecs[tostring(size)]
return formspec
end
local function inventory_id(maker_name)
local id= airutils.modname .. "_" .. maker_name .. "_"
for i=0,5 do
id=id..(math.random(0,9))
end
return id
end
function airutils.load_inventory(self)
if self._inv then
local inv_content = core.deserialize(storage:get_string(self._inv_id))
if inv_content then
self._inv:set_list("main", inv_content)
end
end
end
function airutils.save_inventory(self)
if self._inv then
local inv_content = self._inv:get_list("main")
if inv_content then
for k, v in pairs(inv_content) do
inv_content[k] = v:to_string()
end
local inv_content = core.serialize(inv_content)
storage:set_string(self._inv_id, inv_content)
end
end
end
function airutils.remove_inventory(self)
local inventory = airutils.get_inventory(self)
if inventory then
if inventory:is_empty("main") then
return core.remove_detached_inventory(self._inv_id)
else
local inv_content = inventory:get_list("main")
if inv_content then
local pos = self.object:get_pos()
for k, v in pairs(inv_content) do
local count = 0
for i = 0,v:get_count()-1,1
do
core.add_item({x=pos.x+math.random()-0.5,y=pos.y,z=pos.z+math.random()-0.5},v:get_name())
count = count + 1
if count >= 5 then break end
end
end
end
return core.remove_detached_inventory(self._inv_id)
end
end
return false
end
function airutils.destroy_inventory(self)
airutils.remove_inventory(self)
storage:set_string(self._inv_id, nil)
end
--show inventory form to user
function airutils.show_vehicle_trunk_formspec(self, player, size)
local form = get_formspec_by_size(self, size)
core.show_formspec(player:get_player_name(), airutils.modname .. ":inventory",
form
)
end
function airutils.create_inventory(self, size, owner)
owner = owner or ""
if owner == "" then owner = self.owner end
--core.chat_send_all("slots: " .. size)
if owner ~= nil and owner ~= "" then
if self._inv_id == "" then
self._inv_id = inventory_id(owner)
end
local vehicle_inv = core.create_detached_inventory(self._inv_id, {
allow_move = function(inv, from_list, from_index, to_list, to_index, count, player)
local is_moderator = core.check_player_privs(player, {server=true}) or core.check_player_privs(player, {protection_bypass=true})
if player:get_player_name() ~= owner and is_moderator == false then
return 0
end
return count -- allow moving
end,
allow_put = function(inv, listname, index, stack, player)
local is_moderator = core.check_player_privs(player, {server=true}) or core.check_player_privs(player, {protection_bypass=true})
if player:get_player_name() ~= owner and is_moderator == false then
return 0
end
return stack:get_count() -- allow putting
end,
allow_take = function(inv, listname, index, stack, player)
local is_moderator = core.check_player_privs(player, {server=true}) or core.check_player_privs(player, {protection_bypass=true})
if player:get_player_name() ~= owner and is_moderator == false then
return 0
end
return stack:get_count() -- allow taking
end,
on_put = function(inv, toList, toIndex, stack, player)
airutils.save_inventory(self)
end,
on_take = function(inv, toList, toIndex, stack, player)
airutils.save_inventory(self)
end,
on_move = function(inv, from_list, from_index, to_list, to_index, count, player)
airutils.save_inventory(self)
end,
}, owner)
if size >= 8 then
if vehicle_inv:set_size("main", size) then
vehicle_inv:set_width("main", 8)
end
else
vehicle_inv:set_size("main", size)
end
self._inv = vehicle_inv
airutils.load_inventory(self)
end
end
function airutils.get_inventory(self)
if self._inv then
return core.get_inventory({type="detached", name=self._inv_id})
end
return nil
end
function airutils.list_inventory(self)
local inventory = airutils.get_inventory(self)
if inventory then
local list = inventory.get_list("main")
core.chat_send_all(dump(list))
end
end

View file

@ -0,0 +1,167 @@
--[[airutils.rudder_limit = 30
airutils.elevator_limit = 40]]--
local S = airutils.S
dofile(minetest.get_modpath("airutils") .. DIR_DELIM .. "lib_planes" .. DIR_DELIM .. "utilities.lua")
local function set_yaw_by_mouse(self, dir)
local rotation = self.object:get_rotation()
local rot_y = math.deg(rotation.y)
local total = math.abs(math.floor(rot_y/360))
if rot_y < 0 then rot_y = rot_y + (360*total) end
if rot_y > 360 then rot_y = rot_y - (360*total) end
if rot_y >= 270 and dir <= 90 then dir = dir + 360 end
if rot_y <= 90 and dir >= 270 then dir = dir - 360 end
local intensity = self._yaw_intensity / 10
local command = (rot_y - dir) * intensity
if command < -90 then command = -90
elseif command > 90 then command = 90 end
--minetest.chat_send_all("rotation y: "..rot_y.." - dir: "..dir.." - command: "..command)
self._rudder_angle = (-command * self._rudder_limit)/90
end
local function set_yaw(self, dir, dtime)
local yaw_factor = self._yaw_intensity or 25
if dir == 1 then
self._rudder_angle = math.max(self._rudder_angle-(yaw_factor*dtime),-self._rudder_limit)
elseif dir == -1 then
self._rudder_angle = math.min(self._rudder_angle+(yaw_factor*dtime),self._rudder_limit)
end
end
function airutils.heli_control(self, dtime, hull_direction, longit_speed, longit_drag, nhdir,
later_speed, later_drag, accel, player, is_flying)
--if self.driver_name == nil then return end
local retval_accel = accel
local stop = false
local ctrl
local time_correction = (dtime/airutils.ideal_step)
if time_correction < 1 then time_correction = 1 end
self._vehicle_acc = self._vehicle_acc or 0
-- player control
if player then
ctrl = player:get_player_control()
if self._last_time_command > 0.5 then
self._last_time_command = 0.5
end
if not self._acceleration then self._acceleration = 0 end
if not self._lat_acceleration then self._lat_acceleration = 0 end
if self._engine_running then
--control lift
local collective_up_max = 1.2
local min_angle = self._min_collective
local collective_up = collective_up_max / 10
if ctrl.jump then
self._wing_configuration = self._wing_configuration + collective_up
--end
self._is_going_up = true
elseif ctrl.sneak then
self._wing_configuration = self._wing_configuration - collective_up
--end
else
self._wing_configuration = self._stable_collective
end
if self._wing_configuration < min_angle then self._wing_configuration = min_angle end
local up_limit = (self._wing_angle_of_attack+collective_up_max)
if self._wing_configuration > up_limit then self._wing_configuration = up_limit end
--end lift
else
self._wing_configuration = self._stable_collective or 1
end
local yaw_cmd = 0
if is_flying or self.wheels then
local acc_fraction = (self._max_engine_acc / 40)*time_correction
if ctrl.up then
if longit_speed < self._max_speed then
self._acceleration = self._acceleration + acc_fraction
else
self._acceleration = 0
end
elseif ctrl.down then
if longit_speed > -self._max_speed then
self._acceleration = self._acceleration + (-acc_fraction)
else
self._acceleration = 0
end
else
self._acceleration = 0
end
self._acceleration = math.min(self._acceleration,self._max_engine_acc)
self._acceleration = math.max(self._acceleration,-self._max_engine_acc)
if is_flying then --why double check? because I dont want lateral movement when landed
if ctrl.right then
yaw_cmd = 1
if later_speed < self._max_speed and self._yaw_by_mouse then
self._lat_acceleration = self._lat_acceleration + acc_fraction
else
self._lat_acceleration = 0
end
elseif ctrl.left then
yaw_cmd = -1
if later_speed > -self._max_speed and self._yaw_by_mouse then
self._lat_acceleration = self._lat_acceleration + (-acc_fraction)
else
self._lat_acceleration = 0
end
else
self._lat_acceleration = 0
end
end
else
self._acceleration = 0
self._lat_acceleration = 0
self.object:set_velocity({x=0,y=self.object:get_velocity().y,z=0})
end
self._vehicle_acc = math.min(self._acceleration, self._max_engine_acc)
self._vehicle_acc = math.max(self._acceleration,-self._max_engine_acc)
self._lat_acc = math.min(self._lat_acceleration, self._max_engine_acc)
local hull_acc = vector.multiply(hull_direction,self._vehicle_acc)
local lat_hull_acc = vector.multiply(nhdir,self._lat_acc)
--colocar aceleração lateral aqui
retval_accel=vector.add(retval_accel,hull_acc)
retval_accel=vector.add(retval_accel,lat_hull_acc)
-- yaw
if self._yaw_by_mouse then
local rot_y = math.deg(player:get_look_horizontal())
set_yaw_by_mouse(self, rot_y)
else
set_yaw(self, yaw_cmd, dtime)
end
--I'm desperate, center all!
if ctrl.right and ctrl.left then
self._wing_configuration = self._stable_collective
end
if ctrl.up and ctrl.down and self._last_time_command >= 0.5 then
self._last_time_command = 0
local name = player:get_player_name()
if self._yaw_by_mouse == true then
minetest.chat_send_player(name, core.colorize('#0000ff', S(" >>> Mouse control disabled.")))
self._yaw_by_mouse = false
else
minetest.chat_send_player(name, core.colorize('#0000ff', S(" >>> Mouse control enabled.")))
self._yaw_by_mouse = true
end
end
end
return retval_accel, stop
end

View file

@ -0,0 +1,382 @@
dofile(minetest.get_modpath("airutils") .. DIR_DELIM .. "lib_planes" .. DIR_DELIM .. "global_definitions.lua")
local function engineSoundPlay(self, increment, base)
increment = increment or 0.0
--sound
if self.sound_handle then minetest.sound_stop(self.sound_handle) end
if self.object then
local base_pitch = base
local pitch_adjust = base_pitch + increment
self.sound_handle = minetest.sound_play({name = self._engine_sound},
{object = self.object, gain = 2.0,
pitch = pitch_adjust,
max_hear_distance = 32,
loop = true,})
end
end
local function engine_set_sound_and_animation(self, is_flying, newpitch, newroll)
is_flying = is_flying or false
if self._engine_running then --engine running
if not self.sound_handle then
engineSoundPlay(self, 0.0, 0.9)
end
--self._cmd_snd
if self._snd_last_cmd ~= self._cmd_snd then
local increment
self._snd_last_cmd = self._cmd_snd
if self._cmd_snd then increment = 0.1 else increment = 0.0 end
engineSoundPlay(self, increment, 0.9)
end
self.object:set_animation_frame_speed(100)
else
if is_flying then --autorotation here
if self._snd_last_cmd ~= self._cmd_snd then
local increment
self._snd_last_cmd = self._cmd_snd
if self._cmd_snd then increment = 0.1 else increment = 0.0 end
engineSoundPlay(self, increment, 0.6)
end
self.object:set_animation_frame_speed(70)
else --stop all
if self.sound_handle then
self._snd_last_roll = nil
self._snd_last_pitch = nil
minetest.sound_stop(self.sound_handle)
self.sound_handle = nil
self.object:set_animation_frame_speed(0)
end
end
end
end
function airutils.logic_heli(self)
local velocity = self.object:get_velocity()
local curr_pos = self.object:get_pos()
self._curr_pos = curr_pos --shared
self._last_accel = self.object:get_acceleration()
self._last_time_command = self._last_time_command + self.dtime
if self._last_time_command > 1 then self._last_time_command = 1 end
local player = nil
if self.driver_name then player = minetest.get_player_by_name(self.driver_name) end
local co_pilot = nil
if self.co_pilot and self._have_copilot then co_pilot = minetest.get_player_by_name(self.co_pilot) end
--test collision
airutils.testImpact(self, velocity, curr_pos)
local ctrl = nil
if player then
ctrl = player:get_player_control()
---------------------
-- change the driver
---------------------
if co_pilot and self._have_copilot and self._last_time_command >= 1 then
if self._command_is_given == true then
if ctrl.sneak or ctrl.jump or ctrl.up or ctrl.down or ctrl.right or ctrl.left then
self._last_time_command = 0
--take the control
airutils.transfer_control(self, false)
end
else
if ctrl.sneak == true and ctrl.jump == true then
self._last_time_command = 0
--trasnfer the control to student
airutils.transfer_control(self, true)
end
end
end
end
if not self.object:get_acceleration() then return end
local accel_y = self.object:get_acceleration().y
local rotation = self.object:get_rotation()
local yaw = rotation.y
local newyaw=yaw
local roll = rotation.z
local hull_direction = airutils.rot_to_dir(rotation) --minetest.yaw_to_dir(yaw)
local nhdir = {x=hull_direction.z,y=0,z=-hull_direction.x} -- lateral unit vector
local longit_speed = vector.dot(velocity,hull_direction)
self._longit_speed = longit_speed
local longit_drag = vector.multiply(hull_direction,longit_speed*
longit_speed*self._longit_drag_factor*-1*airutils.sign(longit_speed))
local later_speed = airutils.dot(velocity,nhdir)
--minetest.chat_send_all('later_speed: '.. later_speed)
local later_drag = vector.multiply(nhdir,later_speed*later_speed*
self._later_drag_factor*-1*airutils.sign(later_speed))
local accel = vector.add(longit_drag,later_drag)
local stop = false
local is_flying = true
if self.colinfo then
is_flying = (not self.colinfo.touching_ground)
end
if self.isinliquid == true then
is_flying = false
end
--if self.isonground then is_flying = false end
--if is_flying then minetest.chat_send_all('is flying') end
local is_attached = airutils.checkAttach(self, player)
if self._indicated_speed == nil then self._indicated_speed = 0 end
if not is_attached then
-- for some engine error the player can be detached from the machine, so lets set him attached again
airutils.checkattachBug(self)
end
if self._custom_step_additional_function then
self._custom_step_additional_function(self)
end
--landing light
if self._have_landing_lights then
airutils.landing_lights_operate(self)
end
--smoke and fire
if self._engine_running then
local curr_health_percent = (self.hp_max * 100)/self._max_plane_hp
if curr_health_percent < 20 then
airutils.add_smoke_trail(self, 2)
elseif curr_health_percent < 50 then
airutils.add_smoke_trail(self, 1)
end
else
if self._smoke_spawner and not self._smoke_semaphore then
self._smoke_semaphore = 1 --to set it only one time
minetest.after(5, function()
if self._smoke_spawner then
minetest.delete_particlespawner(self._smoke_spawner)
self._smoke_spawner = nil
self._smoke_semaphore = nil
end
end)
end
end
if (math.abs(velocity.x) < 0.1 and math.abs(velocity.z) < 0.1) and is_flying == false and is_attached == false and self._engine_running == false then
if self._ground_friction then
if not self.isinliquid then self.object:set_velocity({x=0,y=airutils.gravity*self.dtime,z=0}) end
end
engine_set_sound_and_animation(self, false, 0, 0)
return
end
--adjust climb indicator
local y_velocity = 0
if self._engine_running or is_flying then y_velocity = velocity.y end
local climb_rate = y_velocity
if climb_rate > 5 then climb_rate = 5 end
if climb_rate < -5 then
climb_rate = -5
end
-- pitch and roll
local newroll = 0
local newpitch = 0
if ctrl and is_flying then
local command_angle = self._tilt_angle or 0
local max_acc = self._max_engine_acc
local pitch_ammount = (math.abs(self._vehicle_acc or 0) * command_angle) / max_acc
if math.abs(longit_speed) >= self._max_speed then pitch_ammount = command_angle end --gambiarra pra continuar com angulo
pitch_ammount = math.rad(math.min(pitch_ammount, command_angle))
if ctrl.up then newpitch = -pitch_ammount end
if ctrl.down then newpitch = pitch_ammount end
local roll_ammount = (math.abs(self._lat_acc or 0) * command_angle) / max_acc
if math.abs(later_speed) >= self._max_speed then roll_ammount = command_angle end --gambiarra pra continuar com angulo
roll_ammount = math.rad(math.min(roll_ammount, command_angle))
if ctrl.left then newroll = -roll_ammount end
if ctrl.right then newroll = roll_ammount end
if ctrl.up or ctrl.down or ctrl.left or ctrl.right then
self._cmd_snd = true
else
self._cmd_snd = false
end
end
-- new yaw
if math.abs(self._rudder_angle)>1.5 then
local turn_rate = math.rad(self._yaw_turn_rate)
local yaw_turn = self.dtime * math.rad(self._rudder_angle) * turn_rate * 4
newyaw = yaw + yaw_turn
end
---------------------------------
-- end roll
local pilot = player
if self._have_copilot then
if self._command_is_given and co_pilot then
pilot = co_pilot
else
self._command_is_given = false
end
end
------------------------------------------------------
--accell calculation block
------------------------------------------------------
if is_attached or co_pilot then
accel, stop = airutils.heli_control(self, self.dtime, hull_direction,
longit_speed, longit_drag, nhdir, later_speed, later_drag, accel, pilot, is_flying)
end
--end accell
--get disconnected players
airutils.rescueConnectionFailedPassengers(self)
if accel == nil then accel = {x=0,y=0,z=0} end
--lift calculation
accel.y = accel_y
--lets apply some bob in water
if self.isinliquid then
local bob = airutils.minmax(airutils.dot(accel,hull_direction),0.02) -- vertical bobbing
if bob < 0 then bob = 0 end
accel.y = accel.y + bob
local max_pitch = 6
local ref_speed = longit_speed * 20
if ref_speed < 0 then ref_speed = 0 end
local h_vel_compensation = ((ref_speed * 100)/max_pitch)/100
if h_vel_compensation < 0 then h_vel_compensation = 0 end
if h_vel_compensation > max_pitch then h_vel_compensation = max_pitch end
--minetest.chat_send_all(h_vel_compensation)
newpitch = newpitch + (velocity.y * math.rad(max_pitch - h_vel_compensation))
end
local ceiling = 5000
local blade_speed = self._rotor_speed or 15
local limit = (self._max_speed)
if self._engine_running == false then
if is_flying then
blade_speed = self._rotor_idle_speed or 12
if math.abs(longit_speed) > 0.5 then blade_speed = self._rotor_idle_speed + (self._rotor_speed - self._rotor_idle_speed) / 2 end
else
blade_speed = 0.001 --to avoid division by 0
end
end
local new_accel = airutils.getLiftAccel(self, {x=0, y=velocity.y, z=blade_speed}, {x=0, y=accel.y, z=blade_speed/self.dtime}, blade_speed, roll, curr_pos, self._lift, ceiling, self._wing_span)
local y_accell = new_accel.y
new_accel = vector.new(accel)
new_accel.y = y_accell
if velocity.y > limit then new_accel.y = 0 end --it isn't a rocket :/
--wind effects
if airutils.wind and is_flying == true then
local wind = airutils.get_wind(curr_pos, 0.1)
new_accel = vector.add(new_accel, wind)
end
if stop ~= true then --maybe == nil
self._last_accell = new_accel
self.object:move_to(curr_pos)
--airutils.set_acceleration(self.object, new_accel)
--local limit = self._climb_speed
--if new_accel.y > limit then new_accel.y = limit end --it isn't a rocket :/
else
if stop == true then
self._last_accell = vector.new() --self.object:get_acceleration()
self.object:set_acceleration({x=0,y=0,z=0})
self.object:set_velocity({x=0,y=0,z=0})
end
end
if self.wheels then
if is_flying == false then --isn't flying?
--animate wheels
local min_speed_animation = 0.1
if math.abs(velocity.x) > min_speed_animation or math.abs(velocity.z) > min_speed_animation then
self.wheels:set_animation_frame_speed(longit_speed * 10)
else
self.wheels:set_animation_frame_speed(0)
end
else
--stop wheels
self.wheels:set_animation_frame_speed(0)
end
end
------------------------------------------------------
-- end accell
------------------------------------------------------
------------------------------------------------------
-- sound and animation
------------------------------------------------------
local is_ship_attached = self.object:get_attach()
if is_ship_attached then
engine_set_sound_and_animation(self, false, newpitch, newroll) --is attached to a mother ship, so stop all
else
engine_set_sound_and_animation(self, is_flying, newpitch, newroll)
end
------------------------------------------------------
--GAUGES
--minetest.chat_send_all('rate '.. climb_rate)
local climb_angle = airutils.get_gauge_angle(climb_rate)
self._climb_rate = climb_rate
local indicated_speed = longit_speed * 0.9
if indicated_speed < 0 then indicated_speed = 0 end
self._indicated_speed = indicated_speed
local speed_angle = airutils.get_gauge_angle(indicated_speed, -45)
--adjust power indicator
local fixed_power = 60
if self._engine_running == false then fixed_power = 0 end
local power_indicator_angle = airutils.get_gauge_angle(fixed_power/10) + 90
local fuel_in_percent = (self._energy * 1)/self._max_fuel
local energy_indicator_angle = (180*fuel_in_percent)-180
if is_attached then
if self._show_hud then
airutils.update_hud(player, climb_angle, speed_angle, power_indicator_angle, energy_indicator_angle)
else
airutils.remove_hud(player)
end
end
if is_flying == false then
newyaw = yaw
end
if player and self._use_camera_relocation then
--minetest.chat_send_all(dump(newroll))
local new_eye_offset = airutils.camera_reposition(player, newpitch, newroll)
player:set_eye_offset(new_eye_offset, {x = 0, y = 1, z = -30})
end
--apply rotations
self.object:set_rotation({x=newpitch,y=newyaw,z=newroll})
--end
-- calculate energy consumption --
airutils.consumptionCalc(self, accel)
--saves last velocity for collision detection (abrupt stop)
self._last_accel = new_accel
self._last_vel = self.object:get_velocity()
self._last_longit_speed = longit_speed
self._yaw = newyaw
self._roll = newroll
self._pitch = newpitch
end

View file

@ -0,0 +1,8 @@
dofile(minetest.get_modpath("airutils") .. DIR_DELIM .. "lib_copter" .. DIR_DELIM .. "control.lua")
dofile(minetest.get_modpath("airutils") .. DIR_DELIM .. "lib_copter" .. DIR_DELIM .. "entities.lua")

View file

@ -0,0 +1,313 @@
--global constants
airutils.ideal_step = 0.02
--[[airutils.rudder_limit = 30
airutils.elevator_limit = 40]]--
dofile(minetest.get_modpath("airutils") .. DIR_DELIM .. "lib_planes" .. DIR_DELIM .. "utilities.lua")
local S = airutils.S
function airutils.powerAdjust(self,dtime,factor,dir,max_power)
local max = max_power or 100
local add_factor = factor/2
add_factor = add_factor * (dtime/airutils.ideal_step) --adjusting the command speed by dtime
if dir == 1 then
if self._power_lever < max then
self._power_lever = self._power_lever + add_factor
end
if self._power_lever > max then
self._power_lever = max
end
end
if dir == -1 then
if self._power_lever > 0 then
self._power_lever = self._power_lever - add_factor
if self._power_lever < 0 then self._power_lever = 0 end
end
if self._power_lever <= 0 then
self._power_lever = 0
end
end
end
function airutils.control(self, dtime, hull_direction, longit_speed, longit_drag,
later_speed, later_drag, accel, player, is_flying)
--if self.driver_name == nil then return end
local retval_accel = accel
local stop = false
local ctrl = nil
-- player control
if player then
ctrl = player:get_player_control()
if ctrl.aux1 and self._last_time_command > 0.5 then
self._last_time_command = 0
end
----------------------------------
-- flap operation
----------------------------------
if ctrl.aux1 and ctrl.sneak and self._last_time_command >= 0.3 and self._wing_angle_extra_flaps then
self._last_time_command = 0
airutils.flap_operate(self, player)
end
self._acceleration = 0
if self._engine_running then
--engine acceleration calc
local engineacc = (self._power_lever * self._max_engine_acc) / 100;
local factor = 1
--increase power lever
if ctrl.jump then
airutils.powerAdjust(self, dtime, factor, 1)
end
--decrease power lever
if ctrl.sneak then
airutils.powerAdjust(self, dtime, factor, -1)
if self._power_lever <= 0 and is_flying == false then
--break
if longit_speed > 0 then
engineacc = -1
if (longit_speed + engineacc) < 0 then
engineacc = longit_speed * -1
end
end
if longit_speed < 0 then
engineacc = 1
if (longit_speed + engineacc) > 0 then
engineacc = longit_speed * -1
end
end
if math.abs(longit_speed) < 0.2 then
stop = true
end
end
end
--do not exceed
local max_speed = self._max_speed
if longit_speed > max_speed then
engineacc = engineacc - (longit_speed-max_speed)
if engineacc < 0 then engineacc = 0 end
end
self._acceleration = engineacc
else
local paddleacc = 0
if longit_speed < 1.0 then
if ctrl.jump then paddleacc = 0.5 end
end
if longit_speed > -1.0 then
if ctrl.sneak then paddleacc = -0.5 end
end
self._acceleration = paddleacc
end
local hull_acc = vector.multiply(hull_direction,self._acceleration)
retval_accel=vector.add(retval_accel,hull_acc)
--pitch
local pitch_cmd = 0
if self._yaw_by_mouse == true then
airutils.set_pitch_by_mouse(self, player)
else
if ctrl.up then pitch_cmd = 1 elseif ctrl.down then pitch_cmd = -1 end
airutils.set_pitch(self, pitch_cmd, dtime)
end
-- yaw
local yaw_cmd = 0
if self._yaw_by_mouse == true then
local rot_y = math.deg(player:get_look_horizontal())
airutils.set_yaw_by_mouse(self, rot_y)
else
if ctrl.right then yaw_cmd = 1 elseif ctrl.left then yaw_cmd = -1 end
airutils.set_yaw(self, yaw_cmd, dtime)
end
--I'm desperate, center all!
if ctrl.right and ctrl.left then
self._elevator_angle = 0
self._rudder_angle = 0
end
if ctrl.up and ctrl.down and self._last_time_command > 0.5 then
self._last_time_command = 0
local name = player:get_player_name()
if self._yaw_by_mouse == true then
minetest.chat_send_player(name, core.colorize('#0000ff', S(" >>> Mouse control disabled.")))
self._yaw_by_mouse = false
else
minetest.chat_send_player(name, core.colorize('#0000ff', S(" >>> Mouse control enabled.")))
self._yaw_by_mouse = true
end
end
end
if longit_speed > 0 then
if ctrl then
if not (ctrl.right or ctrl.left) then
airutils.rudder_auto_correction(self, longit_speed, dtime)
end
else
airutils.rudder_auto_correction(self, longit_speed, dtime)
end
if airutils.elevator_auto_correction then
self._elevator_angle = airutils.elevator_auto_correction(self, longit_speed, self.dtime, self._max_speed, self._elevator_angle, self._elevator_limit, airutils.ideal_step, 100)
end
end
return retval_accel, stop
end
function airutils.set_pitch_by_mouse(self, player)
local vehicle_rot = self.object:get_rotation()
local rot_x = player:get_look_vertical()-vehicle_rot.x
self._elevator_angle = -(rot_x * self._elevator_limit)*(self._pitch_intensity*10)
if self._elevator_angle > self._elevator_limit then self._elevator_angle = self._elevator_limit end
if self._elevator_angle < -self._elevator_limit then self._elevator_angle = -self._elevator_limit end
end
function airutils.set_pitch(self, dir, dtime)
local pitch_factor = self._pitch_intensity or 0.6
local multiplier = pitch_factor*(dtime/airutils.ideal_step)
if dir == -1 then
--minetest.chat_send_all("cabrando")
self._elevator_angle = math.max(self._elevator_angle-multiplier,-self._elevator_limit)
elseif dir == 1 then
--minetest.chat_send_all("picando")
self._elevator_angle = math.min(self._elevator_angle+multiplier,self._elevator_limit)
end
end
function airutils.set_autopilot_pitch(self, dir, dtime)
local pitch_factor = 0.05
local multiplier = pitch_factor*(dtime/airutils.ideal_step)
if dir == -1 then
--minetest.chat_send_all("cabrando")
self._elevator_angle = math.max(self._elevator_angle-multiplier,-self._elevator_limit)
elseif dir == 1 then
--minetest.chat_send_all("picando")
self._elevator_angle = math.min(self._elevator_angle+multiplier,self._elevator_limit)
end
end
function airutils.set_yaw_by_mouse(self, dir)
local rotation = self.object:get_rotation()
local rot_y = math.deg(rotation.y)
local total = math.abs(math.floor(rot_y/360))
if rot_y < 0 then rot_y = rot_y + (360*total) end
if rot_y > 360 then rot_y = rot_y - (360*total) end
if rot_y >= 270 and dir <= 90 then dir = dir + 360 end
if rot_y <= 90 and dir >= 270 then dir = dir - 360 end
local intensity = self._yaw_intensity / 10
local command = (rot_y - dir) * intensity
if command < -90 then command = -90
elseif command > 90 then command = 90 end
--minetest.chat_send_all("rotation y: "..rot_y.." - dir: "..dir.." - command: "..command)
self._rudder_angle = (-command * self._rudder_limit)/90
end
function airutils.set_yaw(self, dir, dtime)
local yaw_factor = self._yaw_intensity or 25
if dir == 1 then
self._rudder_angle = math.max(self._rudder_angle-(yaw_factor*dtime),-self._rudder_limit)
elseif dir == -1 then
self._rudder_angle = math.min(self._rudder_angle+(yaw_factor*dtime),self._rudder_limit)
end
end
function airutils.rudder_auto_correction(self, longit_speed, dtime)
local factor = 1
if self._rudder_angle > 0 then factor = -1 end
local correction = (self._rudder_limit*(longit_speed/1000)) * factor * (dtime/airutils.ideal_step)
local before_correction = self._rudder_angle
local new_rudder_angle = self._rudder_angle + correction
if math.sign(before_correction) ~= math.sign(new_rudder_angle) then
self._rudder_angle = 0
else
self._rudder_angle = new_rudder_angle
end
end
function airutils.autopilot(self, dtime, hull_direction, longit_speed, accel, curr_pos)
local retval_accel = accel
if not self._have_auto_pilot then return end
local min_attack_angle = self._wing_angle_of_attack or 1.0
local flap = self._wing_angle_extra_flaps or 2
local max_attack_angle = min_attack_angle + flap --1.8
--climb
local velocity = self.object:get_velocity()
local climb_rate = velocity.y * 1.5
if climb_rate > 5 then climb_rate = 5 end
if climb_rate < -5 then
climb_rate = -5
end
self._acceleration = 0
local climb_rate_min = 0.2
local factor = math.abs(climb_rate * 0.1)
if self._engine_running then
--engine acceleration calc
local engineacc = (self._power_lever * self._max_engine_acc) / 100;
--self.engine:set_animation_frame_speed(60 + self._power_lever)
--increase power lever
if climb_rate > climb_rate_min then
airutils.powerAdjust(self, dtime, factor, -1)
end
--decrease power lever
if climb_rate < 0 then
airutils.powerAdjust(self, dtime, factor, 1)
end
--do not exceed
local max_speed = self._max_speed
if longit_speed > max_speed then
engineacc = 0
if engineacc < 0 then engineacc = 0 end
end
self._acceleration = engineacc
end
local hull_acc = vector.multiply(hull_direction,self._acceleration)
retval_accel=vector.add(retval_accel,hull_acc)
--decrease power lever
if climb_rate < 0 then
airutils.set_autopilot_pitch(self, -1, dtime)
--core.chat_send_all("cabrando: "..dump(climb_rate))
elseif climb_rate > climb_rate_min then
airutils.set_autopilot_pitch(self, 1, dtime)
--core.chat_send_all("picando: "..dump(climb_rate))
end
--pitch
--[[if self._angle_of_attack > max_attack_angle then
airutils.set_autopilot_pitch(self, -1, dtime)
elseif self._angle_of_attack < min_attack_angle then
airutils.set_autopilot_pitch(self, 1, dtime)
end]]--
-- yaw
airutils.set_yaw(self, 0, dtime)
if longit_speed > (self._min_speed or 0) then
airutils.rudder_auto_correction(self, longit_speed, dtime)
if airutils.elevator_auto_correction then
--self._elevator_angle = airutils.elevator_auto_correction(self, longit_speed, self.dtime, self._max_speed, self._elevator_angle, self._elevator_limit, airutils.ideal_step, 500)
end
end
return retval_accel
end

View file

@ -0,0 +1,114 @@
function airutils.physics(self)
local friction = self._ground_friction or 0.99
local vel=self.object:get_velocity()
local new_velocity = vector.new()
--buoyancy
local surface = nil
local surfnodename = nil
local spos = airutils.get_stand_pos(self)
if not spos then return end
spos.y = spos.y+0.01
-- get surface height
local snodepos = airutils.get_node_pos(spos)
local surfnode = airutils.nodeatpos(spos)
while surfnode and (surfnode.drawtype == 'liquid' or surfnode.drawtype == 'flowingliquid') do
surfnodename = surfnode.name
surface = snodepos.y +0.5
if surface > spos.y+self.height then break end
snodepos.y = snodepos.y+1
surfnode = airutils.nodeatpos(snodepos)
end
self.isinliquid = surfnodename
if surface then -- standing in liquid
self.isinliquid = true
end
local last_accel = vector.new()
if self._last_accel then
last_accel = vector.new(self._last_accel)
end
if self.isinliquid then
self.water_drag = 0.2
self.isinliquid = true
local height = self.height
local submergence = math.min(surface-spos.y,height)/height
-- local balance = self.buoyancy*self.height
local buoyacc = airutils.gravity*(self.buoyancy-submergence)
--local buoyacc = self._baloon_buoyancy*(self.buoyancy-submergence)
local accell = {
x=-vel.x*self.water_drag,
y=buoyacc-(vel.y*math.abs(vel.y)*0.4),
z=-vel.z*self.water_drag
}
if self.buoyancy >= 1 then self._engine_running = false end
if last_accel then
accell = vector.add(accell,last_accel)
end
new_velocity = vector.multiply(accell,self.dtime)
--airutils.set_acceleration(self.object,accell)
--self.object:move_to(self.object:get_pos())
else
--airutils.set_acceleration(self.object,{x=0,y=airutils.gravity,z=0})
self.isinliquid = false
if last_accel then
last_accel.y = last_accel.y + airutils.gravity --gravity here
new_velocity = vector.multiply(last_accel,self.dtime)
end
--self.object:set_acceleration({x=0,y=new_accel.y, z=0})
end
if self.isonground and not self.isinliquid then
--dumb friction
new_velocity = {x=new_velocity.x*friction,
y=new_velocity.y,
z=new_velocity.z*friction}
-- bounciness
if self.springiness and self.springiness > 0 and self.buoyancy >= 1 then
local vnew = vector.new(new_velocity)
if not self.collided then -- ugly workaround for inconsistent collisions
for _,k in ipairs({'y','z','x'}) do
if new_velocity[k]==0 and math.abs(self.lastvelocity[k])> 0.1 then
vnew[k]=-self.lastvelocity[k]*self.springiness
end
end
end
if not vector.equals(new_velocity,vnew) then
self.collided = true
else
if self.collided then
vnew = vector.new(self.lastvelocity)
end
self.collided = false
end
new_velocity = vnew
end
--damage if the friction is below .97
if self._last_longit_speed then
if friction <= 0.97 and self._last_longit_speed > 0 then
self.hp_max = self.hp_max - 0.001
airutils.setText(self, self._vehicle_name)
end --damage the plane if it have hard friction
end
--self.object:set_velocity(new_velocity)
--new_velocity = vector.subtract(new_velocity,vel)
--fix bug with unexpe3cted moving
if not self.driver_name and math.abs(vel.x) < 0.2 and math.abs(vel.z) < 0.2 then
self.object:set_velocity({x=0,y=airutils.gravity*self.dtime,z=0})
if self.wheels then self.wheels:set_animation_frame_speed(0) end
return
end
end
self.object:add_velocity(new_velocity)
end

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,450 @@
dofile(minetest.get_modpath("airutils") .. DIR_DELIM .. "lib_planes" .. DIR_DELIM .. "global_definitions.lua")
local S = airutils.S
--------------
-- Manual --
--------------
function airutils.getPlaneFromPlayer(player)
local seat = player:get_attach()
if seat then
local plane = seat:get_attach()
return plane
end
return nil
end
function airutils.pilot_formspec(name)
local player = minetest.get_player_by_name(name)
local plane_obj = airutils.getPlaneFromPlayer(player)
if plane_obj == nil then
return
end
local ent = plane_obj:get_luaentity()
local flap_is_down = "false"
local have_flaps = false
if ent._wing_angle_extra_flaps then
if ent._wing_angle_extra_flaps > 0 then
have_flaps = true
end
end
if have_flaps then
if ent._flap then flap_is_down = "true" end
end
local light = "false"
if ent._have_landing_lights then
if ent._land_light then light = "true" end
end
local autopilot = "false"
if ent._have_auto_pilot then
if ent._autopilot then autopilot = "true" end
end
local yaw = "false"
if ent._yaw_by_mouse then yaw = "true" end
local eng_status = "false"
local eng_status_color = "#ff0000"
if ent._engine_running then
eng_status = "true"
eng_status_color = "#00ff00"
end
local ver_pos = 1.0
local basic_form = ""
--basic_form = basic_form.."button[1,"..ver_pos..";4,1;turn_on;Start/Stop Engines]"
basic_form = basic_form.."checkbox[1,"..ver_pos..";turn_on;"..core.colorize(eng_status_color, S("Start/Stop Engines"))..";"..eng_status.."]"
ver_pos = ver_pos + 1.1
basic_form = basic_form.."button[1,"..ver_pos..";4,1;hud;" .. S("Show/Hide Gauges") .. "]"
ver_pos = ver_pos + 1.1
basic_form = basic_form.."button[1,"..ver_pos..";4,1;inventory;" .. S("Show Inventory") .. "]"
ver_pos = ver_pos + 1.5
basic_form = basic_form.."checkbox[1,"..ver_pos..";yaw;" .. S("Yaw by mouse") .. ";"..yaw.."]"
ver_pos = ver_pos + 0.5
basic_form = basic_form.."button[1,"..ver_pos..";4,1;go_out;" .. S("Go Out!") .. "]"
--form second part
local expand_form = false
ver_pos = 1.2 --restart in second collumn
if have_flaps then
basic_form = basic_form.."checkbox[6,"..ver_pos..";flap_is_down;" .. S("Flaps down") .. ";"..flap_is_down.."]"
ver_pos = ver_pos + 0.5
expand_form = true
end
if ent._have_landing_lights then
basic_form = basic_form.."checkbox[6,"..ver_pos..";light;" .. S("Landing Light") .. ";"..light.."]"
ver_pos = ver_pos + 0.5
expand_form = true
end
if ent._have_auto_pilot then
basic_form = basic_form.."checkbox[6,"..ver_pos..";turn_auto_pilot_on;" .. S("Autopilot") .. ";"..autopilot.."]"
ver_pos = ver_pos + 0.5
expand_form = true
end
if ent._have_copilot and name == ent.driver_name then
basic_form = basic_form.."button[6,"..ver_pos..";4,1;copilot_form;" .. S("Co-pilot Manager") .. "]"
ver_pos = ver_pos + 1.25
expand_form = true
end
if ent._have_adf then
basic_form = basic_form.."button[6,"..ver_pos..";4,1;adf_form;" .. S("Adf Manager") .. "]"
ver_pos = ver_pos + 1.1
expand_form = true
end
if ent._have_manual then
basic_form = basic_form.."button[6,5.2;4,1;manual;" .. S("Manual") .. "]"
expand_form = true
end
local form_width = 6
if expand_form then form_width = 11 end
local form = table.concat({
"formspec_version[3]",
"size["..form_width..",7.2]",
}, "")
minetest.show_formspec(name, "lib_planes:pilot_main", form..basic_form)
end
function airutils.manage_copilot_formspec(name)
local player = minetest.get_player_by_name(name)
local plane_obj = airutils.getPlaneFromPlayer(player)
if plane_obj == nil then
return
end
local ent = plane_obj:get_luaentity()
local pass_list = ""
for k, v in pairs(ent._passengers) do
pass_list = pass_list .. v .. ","
end
local basic_form = table.concat({
"formspec_version[3]",
"size[6,4.5]",
}, "")
basic_form = basic_form.."label[1,1.0;" .. S("Bring a copilot") .. ":]"
local max_seats = table.getn(ent._seats)
if ent._have_copilot and max_seats > 2 then --no need to select if there are only 2 occupants
basic_form = basic_form.."dropdown[1,1.5;4,0.6;copilot;"..pass_list..";0;false]"
end
basic_form = basic_form.."button[1,2.5;4,1;pass_control;" .. S("Pass the Control") .. "]"
minetest.show_formspec(name, "lib_planes:manage_copilot", basic_form)
end
function airutils.adf_formspec(name)
local player = minetest.get_player_by_name(name)
local plane_obj = airutils.getPlaneFromPlayer(player)
if plane_obj == nil then
return
end
local ent = plane_obj:get_luaentity()
local adf = "false"
if ent._adf then adf = "true" end
local x = 0
local z = 0
if ent._adf_destiny then
if ent._adf_destiny.x then
if type(ent._adf_destiny.x) ~= nil then
x = math.floor(ent._adf_destiny.x)
end
end
if ent._adf_destiny.z then
if type(ent._adf_destiny.z) ~= nil then
z = math.floor(ent._adf_destiny.z)
end
end
end
local basic_form = table.concat({
"formspec_version[3]",
"size[6,3.5]",
}, "")
basic_form = basic_form.."checkbox[1.0,1.0;adf;" .. S("Auto Direction Find") .. ";"..adf.."]"
basic_form = basic_form.."field[1.0,1.7;1.5,0.6;adf_x;pos x;"..x.."]"
basic_form = basic_form.."field[2.8,1.7;1.5,0.6;adf_z;pos z;"..z.."]"
basic_form = basic_form.."button[4.5,1.7;0.6,0.6;save_adf;" .. S("OK") .. "]"
minetest.show_formspec(name, "lib_planes:adf_main", basic_form)
end
function airutils.pax_formspec(name)
local basic_form = table.concat({
"formspec_version[3]",
"size[6,5]",
}, "")
basic_form = basic_form.."button[1,1.0;4,1;new_seat;" .. S("Change Seat") .. "]"
basic_form = basic_form.."button[1,2.5;4,1;go_out;" .. S("Go Offboard") .. "]"
minetest.show_formspec(name, "lib_planes:passenger_main", basic_form)
end
function airutils.go_out_confirmation_formspec(name)
local basic_form = table.concat({
"formspec_version[3]",
"size[7,2.2]",
}, "")
basic_form = basic_form.."label[0.5,0.5;" .. S("Do you really want to go offboard now?") .. "]"
basic_form = basic_form.."button[1.3,1.0;2,0.8;no;" .. S("No") .. "]"
basic_form = basic_form.."button[3.6,1.0;2,0.8;yes;" .. S("Yes") .. "]"
minetest.show_formspec(name, "lib_planes:go_out_confirmation_form", basic_form)
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname == "lib_planes:go_out_confirmation_form" then
local name = player:get_player_name()
local plane_obj = airutils.getPlaneFromPlayer(player)
if plane_obj == nil then
minetest.close_formspec(name, "lib_planes:go_out_confirmation_form")
return
end
local ent = plane_obj:get_luaentity()
if ent then
if fields.yes then
airutils.dettach_pax(ent, player, true)
end
end
minetest.close_formspec(name, "lib_planes:go_out_confirmation_form")
end
if formname == "lib_planes:adf_main" then
local name = player:get_player_name()
local plane_obj = airutils.getPlaneFromPlayer(player)
if plane_obj == nil then
minetest.chat_send_player(name, core.colorize('#ff0000', S(" >>> There is something wrong with the plane...")))
minetest.close_formspec(name, "lib_planes:adf_main")
return
end
local ent = plane_obj:get_luaentity()
if ent then
if fields.adf then
if ent._adf == true then
ent._adf = false
minetest.chat_send_player(name, core.colorize('#0000ff', S(" >>> ADF deactivated.")))
else
ent._adf = true
minetest.chat_send_player(name, core.colorize('#00ff00', S(" >>> ADF activated.")))
end
end
if fields.save_adf then
if not ent._adf_destiny then ent._adf_destiny = {x=0,z=0} end
if ent._adf_destiny then
if fields.adf_x and fields.adf_z then
if tonumber(fields.adf_x, 10) ~= nil and tonumber(fields.adf_z, 10) ~= nil then
ent._adf_destiny.x = tonumber(fields.adf_x, 10)
ent._adf_destiny.z = tonumber(fields.adf_z, 10)
minetest.chat_send_player(name, core.colorize('#00ff00', S(" >>> Destination written successfully.")))
else
minetest.chat_send_player(name, core.colorize('#ff0000', S(" >>> There is something wrong with the ADF fields values.")))
end
else
minetest.chat_send_player(name, core.colorize('#ff0000', S(" >>> Both ADF fields must be given to complete the operation.")))
end
end
end
else
minetest.chat_send_player(name, core.colorize('#ff0000', S(" >>> There is something wrong on ADF saving...")))
end
minetest.close_formspec(name, "lib_planes:adf_main")
end
if formname == "lib_planes:passenger_main" then
local name = player:get_player_name()
local plane_obj = airutils.getPlaneFromPlayer(player)
if plane_obj == nil then
minetest.close_formspec(name, "lib_planes:passenger_main")
return
end
local ent = plane_obj:get_luaentity()
if ent then
if fields.new_seat then
airutils.dettach_pax(ent, player)
airutils.attach_pax(ent, player)
end
if fields.go_out then
local touching_ground, _ = airutils.check_node_below(plane_obj, 2.5)
if ent.isinliquid or touching_ground then --isn't flying?
airutils.dettach_pax(ent, player)
else
airutils.go_out_confirmation_formspec(name)
end
end
end
minetest.close_formspec(name, "lib_planes:passenger_main")
end
if formname == "lib_planes:pilot_main" then
local name = player:get_player_name()
local plane_obj = airutils.getPlaneFromPlayer(player)
if plane_obj then
local ent = plane_obj:get_luaentity()
if fields.turn_on then
airutils.start_engine(ent)
end
if fields.hud then
if ent._show_hud == true then
ent._show_hud = false
else
ent._show_hud = true
end
end
if fields.go_out then
local touch_point = ent.initial_properties.collisionbox[2]-1.0
-----////
local pos = plane_obj:get_pos()
pos.y = pos.y + touch_point
local node_below = minetest.get_node(pos).name
local nodedef = minetest.registered_nodes[node_below]
local is_on_ground = not nodedef or nodedef.walkable or false -- unknown nodes are solid
if ent.driver_name == name and ent.owner == ent.driver_name then --just the owner can do this
--minetest.chat_send_all(dump(noded))
if is_on_ground then --or clicker:get_player_control().sneak then
--minetest.chat_send_all(dump("is on ground"))
--remove the passengers first
local max_seats = table.getn(ent._seats)
for i = max_seats,1,-1
do
--minetest.chat_send_all("index: "..i.." - "..dump(ent._passengers[i]))
if ent._passengers[i] then
local passenger = minetest.get_player_by_name(ent._passengers[i])
if passenger then airutils.dettach_pax(ent, passenger) end
end
end
ent._instruction_mode = false
else
-- not on ground
if ent.co_pilot then
--give the control to the pax
ent._autopilot = false
airutils.transfer_control(ent, true)
ent._command_is_given = true
ent._instruction_mode = true
end
end
end
airutils.dettach_pax(ent, player)
end
if fields.inventory then
if ent._trunk_slots then
airutils.show_vehicle_trunk_formspec(ent, player, ent._trunk_slots)
end
end
if fields.flap_is_down then
if fields.flap_is_down == "true" then
ent._flap = true
else
ent._flap = false
end
minetest.sound_play("airutils_collision", {
object = ent.object,
max_hear_distance = 15,
gain = 1.0,
fade = 0.0,
pitch = 0.5,
}, true)
end
if fields.light then
if ent._land_light == true then
ent._land_light = false
else
ent._land_light = true
end
end
if fields.yaw then
if ent._yaw_by_mouse == true then
ent._yaw_by_mouse = false
else
ent._yaw_by_mouse = true
end
end
if fields.copilot_form then
airutils.manage_copilot_formspec(name)
end
if fields.adf_form then
airutils.adf_formspec(name)
end
if fields.turn_auto_pilot_on then
if ent._autopilot == true then
ent._autopilot = false
core.chat_send_player(ent.driver_name,S(" >>> Autopilot deactivated"))
else
ent._autopilot = true
core.chat_send_player(ent.driver_name,core.colorize('#00ff00', S(" >>> Autopilot activated")))
end
end
if fields.manual then
if ent._have_manual then
ent._have_manual(name)
end
end
end
minetest.close_formspec(name, "lib_planes:pilot_main")
end
if formname == "lib_planes:manage_copilot" then
local name = player:get_player_name()
local plane_obj = airutils.getPlaneFromPlayer(player)
if plane_obj == nil then
minetest.close_formspec(name, "lib_planes:manage_copilot")
return
end
local ent = plane_obj:get_luaentity()
if fields.copilot then
--look for a free seat first
local is_there_a_free_seat = false
for i = 2,1,-1
do
if ent._passengers[i] == nil then
is_there_a_free_seat = true
break
end
end
--then move the current copilot to a free seat
if ent.co_pilot and is_there_a_free_seat then
local copilot_player_obj = minetest.get_player_by_name(ent.co_pilot)
if copilot_player_obj then
airutils.dettach_pax(ent, copilot_player_obj)
airutils.attach_pax(ent, copilot_player_obj)
else
ent.co_pilot = nil
end
end
--so bring the new copilot
if ent.co_pilot == nil then
local new_copilot_player_obj = minetest.get_player_by_name(fields.copilot)
if new_copilot_player_obj then
airutils.dettach_pax(ent, new_copilot_player_obj)
airutils.attach_pax(ent, new_copilot_player_obj, true)
end
end
end
if fields.pass_control then
if ent._command_is_given == true then
--take the control
airutils.transfer_control(ent, false)
else
--trasnfer the control to student
airutils.transfer_control(ent, true)
end
end
minetest.close_formspec(name, "lib_planes:manage_copilot")
end
end)

View file

@ -0,0 +1,70 @@
function airutils.contains(table, val)
for k,v in pairs(table) do
if k == val then
return v
end
end
return false
end
function airutils.loadFuel(self, player_name)
local player = minetest.get_player_by_name(player_name)
local inv = player:get_inventory()
local itmstck=player:get_wielded_item()
local item_name = ""
if itmstck then item_name = itmstck:get_name() end
local fuel = airutils.contains(airutils.fuel, item_name)
if fuel then
--local stack = ItemStack(item_name .. " 1")
if self._energy < self._max_fuel then
itmstck:set_count(1)
inv:remove_item("main", itmstck)
self._energy = self._energy + fuel
if self._energy > self._max_fuel then self._energy = self._max_fuel end
--local energy_indicator_angle = airutils.get_gauge_angle(self._energy)
--self.fuel_gauge:set_attach(self.object,'',self._gauge_fuel_position,{x=0,y=0,z=energy_indicator_angle})
end
return true
end
return false
end
function airutils.consumptionCalc(self, accel)
if accel == nil then return end
if self._energy > 0 and self._engine_running and accel ~= nil then
local divisor = 700000
if self._fuel_consumption_divisor then divisor = self._fuel_consumption_divisor end
local consumed_power = 0
local parent_obj = self.object:get_attach()
if not parent_obj then
if self._rotor_speed then
--is an helicopter
consumed_power = 50/divisor --fixed rpm
else
--is a normal plane
consumed_power = self._power_lever/divisor
end
end
--minetest.chat_send_all('consumed: '.. consumed_power)
self._energy = self._energy - consumed_power;
local energy_indicator_angle = airutils.get_gauge_angle(self._energy)
if self.fuel_gauge then
if self.fuel_gauge:get_luaentity() then
self.fuel_gauge:set_attach(self.object,'',self._gauge_fuel_position,{x=0,y=0,z=energy_indicator_angle})
end
end
end
if self._energy <= 0 and self._engine_running and accel ~= nil then
self._engine_running = false
self._autopilot = false
if self.sound_handle then minetest.sound_stop(self.sound_handle) end
self.object:set_animation_frame_speed(0)
end
end

View file

@ -0,0 +1,134 @@
--[[
local function get_pointer(pointer_angle, gauge_center_x, gauge_center_y, full_pointer)
full_pointer = full_pointer or 1
local retval = ""
local ind_pixel = "airutils_ind_box_2.png"
local pointer_img_size = 8
local pointer_rad = math.rad(pointer_angle)
local dim = 2*(pointer_img_size/2)
local pos_x = math.sin(pointer_rad) * dim
local pos_y = math.cos(pointer_rad) * dim
retval = retval..(gauge_center_x+pos_x)..","..(gauge_center_y+pos_y).."="..ind_pixel..":"
dim = 4*(pointer_img_size/2)
pos_x = math.sin(pointer_rad) * dim
pos_y = math.cos(pointer_rad) * dim
retval = retval..(gauge_center_x+pos_x)..","..(gauge_center_y+pos_y).."="..ind_pixel..":"
dim = 6*(pointer_img_size/2)
pos_x = math.sin(pointer_rad) * dim
pos_y = math.cos(pointer_rad) * dim
retval = retval..(gauge_center_x+pos_x)..","..(gauge_center_y+pos_y).."="..ind_pixel..":"
if full_pointer == 1 then
dim = 8*(pointer_img_size/2)
pos_x = math.sin(pointer_rad) * dim
pos_y = math.cos(pointer_rad) * dim
retval = retval..(gauge_center_x+pos_x)..","..(gauge_center_y+pos_y).."="..ind_pixel..":"
dim = 10*(pointer_img_size/2)
pos_x = math.sin(pointer_rad) * dim
pos_y = math.cos(pointer_rad) * dim
retval = retval..(gauge_center_x+pos_x)..","..(gauge_center_y+pos_y).."="..ind_pixel..":"
end
return retval
end
]]--
function airutils.plot_altimeter_gauge(self, scale, place_x, place_y)
local bg_width_height = 100
local pointer_img = 8
local gauge_center = (bg_width_height / 2) - (pointer_img/2)
local gauge_center_x = place_x + gauge_center
local gauge_center_y = place_y + gauge_center
--altimeter
--[[local altitude = (height / 0.32) / 100
local hour, minutes = math.modf( altitude )
hour = math.fmod (hour, 10)
minutes = minutes * 100
minutes = (minutes * 100) / 100
local minute_angle = (minutes*-360)/100
local hour_angle = (hour*-360)/10 + ((minute_angle*36)/360)]]--
--[[
#### `[combine:<w>x<h>:<x1>,<y1>=<file1>:<x2>,<y2>=<file2>:...`
* `<w>`: width
* `<h>`: height
* `<x>`: x position
* `<y>`: y position
* `<file>`: texture to combine
Creates a texture of size `<w>` times `<h>` and blits the listed files to their
specified coordinates.
]]--
local altimeter = "^[resize:"..scale.."x"..scale.."^[combine:"..bg_width_height.."x"..bg_width_height..":"
..place_x..","..place_y.."=airutils_altimeter_gauge.png:"
--altimeter = altimeter..get_pointer(minute_angle+180, gauge_center_x, gauge_center_y, 1)
--altimeter = altimeter..get_pointer(hour_angle+180, gauge_center_x, gauge_center_y, 0)
return altimeter
end
function airutils.plot_fuel_gauge(self, scale, place_x, place_y)
local bg_width_height = 100
local pointer_img = 8
local gauge_center = (bg_width_height / 2) - (pointer_img/2)
local gauge_center_x = place_x + gauge_center
local gauge_center_y = place_y + gauge_center
--local fuel_percentage = (curr_level*100)/max_level
--local fuel_angle = -(fuel_percentage*180)/100
--minetest.chat_send_all(dump(fuel_angle))
local fuel = "^[resize:"..scale.."x"..scale.."^[combine:"..bg_width_height.."x"..bg_width_height..":"
..place_x..","..place_y.."=airutils_fuel_gauge.png:"
--fuel = fuel..get_pointer(fuel_angle-90, gauge_center_x, gauge_center_y, 1)
return fuel
end
function airutils.plot_speed_gauge(self, scale, place_x, place_y)
local bg_width_height = 100
local pointer_img = 8
local gauge_center = (bg_width_height / 2) - (pointer_img/2)
local gauge_center_x = place_x + gauge_center
local gauge_center_y = place_y + gauge_center
--local speed_percentage = (curr_level*100)/max_level
--local speed_angle = -(speed_percentage*350)/100
--minetest.chat_send_all(dump(fuel_angle))
local speed = "^[resize:"..scale.."x"..scale.."^[combine:"..bg_width_height.."x"..bg_width_height..":"
..place_x..","..place_y.."=airutils_speed_gauge.png:"
--fuel = fuel..get_pointer(speed_angle-180, gauge_center_x, gauge_center_y, 1)
return speed
end
function airutils.plot_power_gauge(self, scale, place_x, place_y)
local bg_width_height = 100
local pointer_img = 8
local gauge_center = (bg_width_height / 2) - (pointer_img/2)
local gauge_center_x = place_x + gauge_center
local gauge_center_y = place_y + gauge_center
--local speed_percentage = (curr_level*100)/max_level
--local speed_angle = -(speed_percentage*350)/100
--minetest.chat_send_all(dump(fuel_angle))
local rpm = "^[resize:"..scale.."x"..scale.."^[combine:"..bg_width_height.."x"..bg_width_height..":"
..place_x..","..place_y.."=airutils_rpm_gauge.png:"
--fuel = fuel..get_pointer(speed_angle-180, gauge_center_x, gauge_center_y, 1)
return rpm
end

View file

@ -0,0 +1,8 @@
--
-- constants
--
airutils.vector_up = vector.new(0, 1, 0)
--set min y-pos above which airplanes are seen on radar
airutils.radarMinHeight = 30

View file

@ -0,0 +1,328 @@
airutils.hud_list = {}
local S = airutils.S
function airutils.animate_gauge(player, ids, prefix, x, y, angle)
local angle_in_rad = math.rad(angle + 180)
local dim = 10
local pos_x = math.sin(angle_in_rad) * dim
local pos_y = math.cos(angle_in_rad) * dim
player:hud_change(ids[prefix .. "2"], "offset", {x = pos_x + x, y = pos_y + y})
dim = 20
pos_x = math.sin(angle_in_rad) * dim
pos_y = math.cos(angle_in_rad) * dim
player:hud_change(ids[prefix .. "3"], "offset", {x = pos_x + x, y = pos_y + y})
dim = 30
pos_x = math.sin(angle_in_rad) * dim
pos_y = math.cos(angle_in_rad) * dim
player:hud_change(ids[prefix .. "4"], "offset", {x = pos_x + x, y = pos_y + y})
dim = 40
pos_x = math.sin(angle_in_rad) * dim
pos_y = math.cos(angle_in_rad) * dim
player:hud_change(ids[prefix .. "5"], "offset", {x = pos_x + x, y = pos_y + y})
dim = 50
pos_x = math.sin(angle_in_rad) * dim
pos_y = math.cos(angle_in_rad) * dim
player:hud_change(ids[prefix .. "6"], "offset", {x = pos_x + x, y = pos_y + y})
dim = 60
pos_x = math.sin(angle_in_rad) * dim
pos_y = math.cos(angle_in_rad) * dim
player:hud_change(ids[prefix .. "7"], "offset", {x = pos_x + x, y = pos_y + y})
end
function airutils.update_hud(player, climb, speed, power, fuel)
local player_name = player:get_player_name()
local screen_pos_y = -150
local screen_pos_x = 10
local clb_gauge_x = screen_pos_x + 75
local clb_gauge_y = screen_pos_y + 1
local sp_gauge_x = screen_pos_x + 170
local sp_gauge_y = clb_gauge_y
local pwr_gauge_x = screen_pos_x + 330
local pwr_gauge_y = clb_gauge_y
local fu_gauge_x = screen_pos_x + 340
local fu_gauge_y = clb_gauge_y
local ids = airutils.hud_list[player_name]
if ids then
airutils.animate_gauge(player, ids, "clb_pt_", clb_gauge_x, clb_gauge_y, climb)
airutils.animate_gauge(player, ids, "sp_pt_", sp_gauge_x, sp_gauge_y, speed)
airutils.animate_gauge(player, ids, "pwr_pt_", pwr_gauge_x, pwr_gauge_y, power)
airutils.animate_gauge(player, ids, "fu_pt_", fu_gauge_x, fu_gauge_y, fuel)
else
ids = {}
ids["title"] = player:hud_add({
hud_elem_type = "text",
position = {x = 0, y = 1},
offset = {x = screen_pos_x +140, y = screen_pos_y -100},
text = S("Flight Information"),
alignment = 0,
scale = { x = 100, y = 30},
number = 0xFFFFFF,
})
ids["bg"] = player:hud_add({
hud_elem_type = "image",
position = {x = 0, y = 1},
offset = {x = screen_pos_x, y = screen_pos_y},
text = "airutils_hud_panel.png",
scale = { x = 0.5, y = 0.5},
alignment = { x = 1, y = 0 },
})
ids["clb_pt_1"] = player:hud_add({
hud_elem_type = "image",
position = {x = 0, y = 1},
offset = {x = clb_gauge_x, y = clb_gauge_y},
text = "airutils_ind_box.png",
scale = { x = 6, y = 6},
alignment = { x = 1, y = 0 },
})
ids["clb_pt_2"] = player:hud_add({
hud_elem_type = "image",
position = {x = 0, y = 1},
offset = {x = clb_gauge_x, y = clb_gauge_y},
text = "airutils_ind_box.png",
scale = { x = 6, y = 6},
alignment = { x = 1, y = 0 },
})
ids["clb_pt_3"] = player:hud_add({
hud_elem_type = "image",
position = {x = 0, y = 1},
offset = {x = clb_gauge_x, y = clb_gauge_y},
text = "airutils_ind_box.png",
scale = { x = 6, y = 6},
alignment = { x = 1, y = 0 },
})
ids["clb_pt_4"] = player:hud_add({
hud_elem_type = "image",
position = {x = 0, y = 1},
offset = {x = clb_gauge_x, y = clb_gauge_y},
text = "airutils_ind_box.png",
scale = { x = 6, y = 6},
alignment = { x = 1, y = 0 },
})
ids["clb_pt_5"] = player:hud_add({
hud_elem_type = "image",
position = {x = 0, y = 1},
offset = {x = clb_gauge_x, y = clb_gauge_y},
text = "airutils_ind_box.png",
scale = { x = 6, y = 6},
alignment = { x = 1, y = 0 },
})
ids["clb_pt_6"] = player:hud_add({
hud_elem_type = "image",
position = {x = 0, y = 1},
offset = {x = clb_gauge_x, y = clb_gauge_y},
text = "airutils_ind_box.png",
scale = { x = 6, y = 6},
alignment = { x = 1, y = 0 },
})
ids["clb_pt_7"] = player:hud_add({
hud_elem_type = "image",
position = {x = 0, y = 1},
offset = {x = clb_gauge_x, y = clb_gauge_y},
text = "airutils_ind_box.png",
scale = { x = 6, y = 6},
alignment = { x = 1, y = 0 },
})
ids["sp_pt_1"] = player:hud_add({
hud_elem_type = "image",
position = {x = 0, y = 1},
offset = {x = sp_gauge_x, y = sp_gauge_y},
text = "airutils_ind_box.png",
scale = { x = 6, y = 6},
alignment = { x = 1, y = 0 },
})
ids["sp_pt_2"] = player:hud_add({
hud_elem_type = "image",
position = {x = 0, y = 1},
offset = {x = sp_gauge_x, y = sp_gauge_y},
text = "airutils_ind_box.png",
scale = { x = 6, y = 6},
alignment = { x = 1, y = 0 },
})
ids["sp_pt_3"] = player:hud_add({
hud_elem_type = "image",
position = {x = 0, y = 1},
offset = {x = sp_gauge_x, y = sp_gauge_y},
text = "airutils_ind_box.png",
scale = { x = 6, y = 6},
alignment = { x = 1, y = 0 },
})
ids["sp_pt_4"] = player:hud_add({
hud_elem_type = "image",
position = {x = 0, y = 1},
offset = {x = sp_gauge_x, y = sp_gauge_y},
text = "airutils_ind_box.png",
scale = { x = 6, y = 6},
alignment = { x = 1, y = 0 },
})
ids["sp_pt_5"] = player:hud_add({
hud_elem_type = "image",
position = {x = 0, y = 1},
offset = {x = sp_gauge_x, y = sp_gauge_y},
text = "airutils_ind_box.png",
scale = { x = 6, y = 6},
alignment = { x = 1, y = 0 },
})
ids["sp_pt_6"] = player:hud_add({
hud_elem_type = "image",
position = {x = 0, y = 1},
offset = {x = sp_gauge_x, y = sp_gauge_y},
text = "airutils_ind_box.png",
scale = { x = 6, y = 6},
alignment = { x = 1, y = 0 },
})
ids["sp_pt_7"] = player:hud_add({
hud_elem_type = "image",
position = {x = 0, y = 1},
offset = {x = sp_gauge_x, y = sp_gauge_y},
text = "airutils_ind_box.png",
scale = { x = 6, y = 6},
alignment = { x = 1, y = 0 },
})
ids["pwr_pt_1"] = player:hud_add({
hud_elem_type = "image",
position = {x = 0, y = 1},
offset = {x = pwr_gauge_x, y = pwr_gauge_y},
text = "airutils_ind_box.png",
scale = { x = 6, y = 6},
alignment = { x = 1, y = 0 },
})
ids["pwr_pt_2"] = player:hud_add({
hud_elem_type = "image",
position = {x = 0, y = 1},
offset = {x = pwr_gauge_x, y = pwr_gauge_y},
text = "airutils_ind_box.png",
scale = { x = 6, y = 6},
alignment = { x = 1, y = 0 },
})
ids["pwr_pt_3"] = player:hud_add({
hud_elem_type = "image",
position = {x = 0, y = 1},
offset = {x = pwr_gauge_x, y = pwr_gauge_y},
text = "airutils_ind_box.png",
scale = { x = 6, y = 6},
alignment = { x = 1, y = 0 },
})
ids["pwr_pt_4"] = player:hud_add({
hud_elem_type = "image",
position = {x = 0, y = 1},
offset = {x = pwr_gauge_x, y = pwr_gauge_y},
text = "airutils_ind_box.png",
scale = { x = 6, y = 6},
alignment = { x = 1, y = 0 },
})
ids["pwr_pt_5"] = player:hud_add({
hud_elem_type = "image",
position = {x = 0, y = 1},
offset = {x = pwr_gauge_x, y = pwr_gauge_y},
text = "airutils_ind_box.png",
scale = { x = 6, y = 6},
alignment = { x = 1, y = 0 },
})
ids["pwr_pt_6"] = player:hud_add({
hud_elem_type = "image",
position = {x = 0, y = 1},
offset = {x = pwr_gauge_x, y = pwr_gauge_y},
text = "airutils_ind_box.png",
scale = { x = 6, y = 6},
alignment = { x = 1, y = 0 },
})
ids["pwr_pt_7"] = player:hud_add({
hud_elem_type = "image",
position = {x = 0, y = 1},
offset = {x = pwr_gauge_x, y = pwr_gauge_y},
text = "airutils_ind_box.png",
scale = { x = 6, y = 6},
alignment = { x = 1, y = 0 },
})
ids["fu_pt_1"] = player:hud_add({
hud_elem_type = "image",
position = {x = 0, y = 1},
offset = {x = fu_gauge_x, y = fu_gauge_y},
text = "airutils_ind_box.png",
scale = { x = 6, y = 6},
alignment = { x = 1, y = 0 },
})
ids["fu_pt_2"] = player:hud_add({
hud_elem_type = "image",
position = {x = 0, y = 1},
offset = {x = fu_gauge_x, y = fu_gauge_y},
text = "airutils_ind_box.png",
scale = { x = 6, y = 6},
alignment = { x = 1, y = 0 },
})
ids["fu_pt_3"] = player:hud_add({
hud_elem_type = "image",
position = {x = 0, y = 1},
offset = {x = fu_gauge_x, y = fu_gauge_y},
text = "airutils_ind_box.png",
scale = { x = 6, y = 6},
alignment = { x = 1, y = 0 },
})
ids["fu_pt_4"] = player:hud_add({
hud_elem_type = "image",
position = {x = 0, y = 1},
offset = {x = fu_gauge_x, y = fu_gauge_y},
text = "airutils_ind_box.png",
scale = { x = 6, y = 6},
alignment = { x = 1, y = 0 },
})
ids["fu_pt_5"] = player:hud_add({
hud_elem_type = "image",
position = {x = 0, y = 1},
offset = {x = fu_gauge_x, y = fu_gauge_y},
text = "airutils_ind_box.png",
scale = { x = 6, y = 6},
alignment = { x = 1, y = 0 },
})
ids["fu_pt_6"] = player:hud_add({
hud_elem_type = "image",
position = {x = 0, y = 1},
offset = {x = fu_gauge_x, y = fu_gauge_y},
text = "airutils_ind_box.png",
scale = { x = 6, y = 6},
alignment = { x = 1, y = 0 },
})
ids["fu_pt_7"] = player:hud_add({
hud_elem_type = "image",
position = {x = 0, y = 1},
offset = {x = fu_gauge_x, y = fu_gauge_y},
text = "airutils_ind_box.png",
scale = { x = 6, y = 6},
alignment = { x = 1, y = 0 },
})
airutils.hud_list[player_name] = ids
end
end
function airutils.remove_hud(player)
if player then
local player_name = player:get_player_name()
--minetest.chat_send_all(player_name)
local ids = airutils.hud_list[player_name]
if ids then
--player:hud_remove(ids["altitude"])
--player:hud_remove(ids["time"])
for key in pairs(ids) do
player:hud_remove(ids[key])
end
end
airutils.hud_list[player_name] = nil
end
end

View file

@ -0,0 +1,19 @@
dofile(minetest.get_modpath("airutils") .. DIR_DELIM .. "lib_planes" .. DIR_DELIM .. "global_definitions.lua")
dofile(minetest.get_modpath("airutils") .. DIR_DELIM .. "lib_planes" .. DIR_DELIM .. "control.lua")
dofile(minetest.get_modpath("airutils") .. DIR_DELIM .. "lib_planes" .. DIR_DELIM .. "fuel_management.lua")
dofile(minetest.get_modpath("airutils") .. DIR_DELIM .. "lib_planes" .. DIR_DELIM .. "custom_physics.lua")
dofile(minetest.get_modpath("airutils") .. DIR_DELIM .. "lib_planes" .. DIR_DELIM .. "utilities.lua")
dofile(minetest.get_modpath("airutils") .. DIR_DELIM .. "lib_planes" .. DIR_DELIM .. "entities.lua")
dofile(minetest.get_modpath("airutils") .. DIR_DELIM .. "lib_planes" .. DIR_DELIM .. "forms.lua")
dofile(minetest.get_modpath("airutils") .. DIR_DELIM .. "lib_planes" .. DIR_DELIM .. "gauges.lua")
--
-- helpers and co.
--
--
-- items
--

File diff suppressed because it is too large Load diff

83
mods/airutils/light.lua Normal file
View file

@ -0,0 +1,83 @@
function airutils.get_xz_from_hipotenuse(orig_x, orig_z, yaw, distance)
--cara, o minetest é bizarro, ele considera o eixo no sentido ANTI-HORÁRIO... Então pra equação funcionar, subtrair o angulo de 360 antes
yaw = math.rad(360) - yaw
local z = (math.cos(yaw)*distance) + orig_z
local x = (math.sin(yaw)*distance) + orig_x
return x, z
end
minetest.register_node("airutils:light", {
drawtype = "airlike",
--tile_images = {"airutils_light.png"},
inventory_image = minetest.inventorycube("airutils_light.png"),
paramtype = "light",
walkable = false,
is_ground_content = true,
light_propagates = true,
sunlight_propagates = true,
light_source = 14,
selection_box = {
type = "fixed",
fixed = {0, 0, 0, 0, 0, 0},
},
})
function airutils.remove_light(self)
if self._light_old_pos then
--force the remotion of the last light
minetest.add_node(self._light_old_pos, {name="air"})
self._light_old_pos = nil
end
end
function airutils.swap_node(self, pos)
local target_pos = pos
local have_air = false
local node = nil
local count = 0
while have_air == false and count <= 3 do
node = minetest.get_node(target_pos)
if node.name == "air" then
have_air = true
break
end
count = count + 1
target_pos.y = target_pos.y + 1
end
if have_air then
minetest.set_node(target_pos, {name='airutils:light'})
airutils.remove_light(self)
self._light_old_pos = target_pos
return true
end
return false
end
function airutils.put_light(self)
local pos = self.object:get_pos()
pos.y = pos.y + 1
local yaw = self.object:get_yaw()
local lx, lz = airutils.get_xz_from_hipotenuse(pos.x, pos.z, yaw, 10)
local light_pos = {x=lx, y=pos.y, z=lz}
local cast = minetest.raycast(pos, light_pos, false, false)
local thing = cast:next()
local was_set = false
while thing do
if thing.type == "node" then
local ipos = thing.intersection_point
if ipos then
was_set = airutils.swap_node(self, ipos)
end
end
thing = cast:next()
end
if was_set == false then
local n = minetest.get_node_or_nil(light_pos)
if n and n.name == 'air' then
airutils.swap_node(self, light_pos)
end
end
end

View file

@ -0,0 +1,85 @@
# textdomain: airutils
Bio Fuel=Biotreibstoff
Biofuel Distiller=Biotreibstoff-Brenner
Fuel Distiller=Treibstoff-Destilliergerät
Fuel Distiller (FULL)=Treibstoff-Destilliergerät (VOLL)
Fuel Distiller @1% done=Treibstoff-Destilliergerät @1% fertig
PAPI=PAPI
left side=linke Seite
right side=rechte Seite
right_side=rechte_seite
Owned by: @1=Gehört: @1
Repair Tool=Reparaturwerkzeug
Tug tool for airport=Schleppwerkzeug für den Flughafen
@1 is protected by @2.=@1 ist geschützt von @2.
@1 is protected.=@1 ist geschützt.
Wind Indicator=Windanzeiger
>>> The wind direction now is @1= >>> Die Windrichtung ist nun @1
Wind Direction Indicator=Windrichtungsanzeiger
Node is protected=Block ist geschützt
Current hp: = Aktuelle Lp:
Nice @1 of @2.@3= Schöne(r/s) @1 von @2.@3
>>> The captain got the control.= >>> Der Kaptain übernimmt die Kontrolle.
>>> The control is with you now.= >>> Du hast nun die Kontrolle.
>>> The control was given.= >>> Die Kontrolle wurde erteilt.
Enable/disable explosion blast damage=Explosionsschaden aktivieren/deaktivieren
>>> Blast damage by explosion is disabled=Explosionsschaden ist deaktiviert.
>>> Blast damage by explosion is enabled=Explosionsschaden ist aktiviert.
Transfer the property of a plane to another player=Überträgt die Eigentümerschaft des Fluggerätes an einen anderen Spieler.
>>> This plane now is property of: = >>> Dieses Fluggerät ist nun Eigentum von:
>>> only the owner or moderators can transfer this airplane= >>> Nur der Eigentümer oder Moderator kann die Eigentümerschaft ändern.
>>> the target player must be logged in= >>> der Zielspieler muß eingeloggt sein.
>>> you are not inside a plane to perform the command= >>> du sitzt in keinem Fluggerät um dieses Kommando zu geben
Ejects from a plane=Wirft dich aus dem Fluggerät
>>> you are not inside a plane= >>> du sitzt in keinem Fluggerät
Enables/disables the ground effect (for debug purposes)=Ein/Ausschaltet den Bodeneffekt (zur Fehlersuche)
>>> Ground effect was turned on.= >>> Bodeneffekt wurde eingeschalten.
>>> Ground effect was turned off.=>>> Bodeneffekt wurde ausgeschalten.
>>> You need 'server' priv to run this command.= >>> Du brauchst 'server'-rechte um dieses Kommando auszuführen.
Enables/disables the lift printing (for debug purposes)=Ein/Ausschalten des Lift schreibens (zur Fehlersuche)
>>> Lift printing turned on.= >>> Lift schreiben eingeschalten.
>>> Lift printing turned off.= >>> Lift schreiben ausgeschalten.
>>> Mouse control disabled.= >>> Mauslenkung ausgeschalten.
>>> Mouse control enabled.= >>> Mauslenkung eingeschalten.
>>> Autopilot deactivated= >>> Autopilot ausgeschalten
>>> Autopilot on= >>> Autopilot eingeschalten
>>> Flaps retracted due for overspeed= >>> Klappen eingefahren wegen Hochgeschwindigkeit
You need steel ingots in your inventory to perform this repair.=Du brauchst Eisenbarren in einem Inventar um das zu reparieren.
Start/Stop Engines=Starte/Stoppe Maschinen
Show/Hide Gauges=Blende Messgeräte ein/aus
Show Inventory=Zeige Inventar
Yaw by mouse=Lenke mit Maus
Go Out!=Steig aus!
Flaps down=Klappen unten
Landing Light=Landelicht
Autopilot=Autopilot
Co-pilot Manager=Co-Pilot Manager
Adf Manager=Adf Manager
Manual=Manuell
Bring a copilot=Bring einen Copiloten
Pass the Control=Übergebe die Kontrolle
Auto Direction Find=Automatischer Richtungsfinder
OK=OK
Change Seat=Wechlse Sitzplatz
Go Offboard=Aussteigen
Do you really want to go offboard now?=Du willst jetzt wirklich aussteigen?
No=Nein
Yes=Ja
>>> There is something wrong with the plane...= >>> Da stimmt was nicht mit dem Fluggerät
>>> ADF deactivated.= >>> ADF deaktiviert
>>> ADF activated.= >>> ADF aktiviert.
>>> Destination written successfully.= >>> Ziel erfolgreich eingetragen
>>> There is something wrong with the ADF fields values.=Mit den Werten der ADF-Felder ist etwas nicht in Ordnung
>>> Both ADF fields must be given to complete the operation.= >>> Beide ADF-Felder müssen angegeben werden, damit der Vorgang abgeschlossen werden kann
>>> There is something wrong on ADF saving...= >>> Da stimmt etwas nicht mit dem ADF speichern
Flight Information=Fluginformation
>>> You need the priv= >>> Du brauchst das Recht
to fly this plane.=um das Fluggerät zu fliegen.
>>> The engine is damaged, start procedure failed.= >>> Die Maschine ist beschädigt, starten fehlgeschlagen.
>>> Flap down=>>> Klappen unten
>>> Flap up=>>> Klappen oben
>>> You cannot claim this scrap yet, wait some minutes.=Du kannst diesen Schrott noch nicht beanspruchen, warte ein paar Minuten
Sorry, but this module doesn't work when SkinsDb and Armor are instaled together.=Entschuldige, aber dieses Modul funktioniert nicht, wenn SkinsDb und Armor zusammen installiert ist.
Something isn't working...=Etwas funktioniert nicht...
Set Player Texture=Wähle Spielertextur
The isn't activated as secure. Aborting=Das ist zur Sicherheit nicht aktiviert. Abbruch

View file

@ -0,0 +1,85 @@
# textdomain: airutils
Bio Fuel=Biocarburant
Biofuel Distiller=Raffineur de Biocarburant
Fuel Distiller=Raffineur de Carburant
Fuel Distiller (FULL)=Raffineur de Carburant (PLEIN)
Fuel Distiller @1% done=Raffineur de Carburant : @1% traité
PAPI=PAPI
left side=coté gauche
right side=coté droit
right_side=coté_droit
Owned by: @1=Propriété de @1
Repair Tool=Outil de Réparation
Tug tool for airport=Remorqueur d'aéroport
@1 is protected by @2.=@1 est protégé par @2.
@1 is protected.=@1 est protégé.
Wind Indicator=Girouette
>>> The wind direction now is @1= >>> La direction actuelle du vent est @1
Wind Direction Indicator=Manche à Air
Node is protected=Nœud protégé
Current hp: = Points de vie :
Nice @1 of @2.@3=Joli(e) @1 de @2.@3
>>> The captain got the control.=>>> Le commandant de bord a repris la main.
>>> The control is with you now.=>>> Vous avez la main.
>>> The control was given.=>>> Vous avez donné la main.
Enable/disable explosion blast damage=Activer/Désactiver les dégats d'explosion
>>> Blast damage by explosion is disabled=>>> Les dégats d'explosion sont désactivés
>>> Blast damage by explosion is enabled=>>> Les dégats d'explosion sont activés
Transfer the property of a plane to another player=Transférer la propriéte d'un avion à un autre joueur
>>> This plane now is property of: = >>> Cet avion est désormais la propriété de :
>>> only the owner or moderators can transfer this airplane= >>> Seuls son propriétaire ou un modérateur peuvent transférer cet avion
>>> the target player must be logged in= >>> Le nouveau propriétaire doit être connecté
>>> you are not inside a plane to perform the command= >>> Vous devez être dans un avion pour exécuter cette commande
Ejects from a plane=Ejectez-vous de l'avion
>>> you are not inside a plane= >>> Vous n'êtes pas à l'intérieur d'un avion
Enables/disables the ground effect (for debug purposes)=Activer/Désactiver l'effet de sol (pour déboguer)
>>> Ground effect was turned on.= >>> L'effet de sol est activé.
>>> Ground effect was turned off.= >>> L'effet de sol est désactivé.
>>> You need 'server' priv to run this command.= >>> Vous devez avoir le privilège 'server' pour exécuter cette commande.
Enables/disables the lift printing (for debug purposes)=Activer/Désactiver le débogage de sustenstation
>>> Lift printing turned on.= >>> Débogage de sustenstation activé.
>>> Lift printing turned off.= >>> Débogage de sustenstation desactivé.
>>> Mouse control disabled.= >>> Commande à la souris désactivée.
>>> Mouse control enabled.= >>> Commande à la souris activée.
>>> Autopilot deactivated= >>> Autopilote désactivé
>>> Autopilot on= >>> Autopilote activé
>>> Flaps retracted due for overspeed= >>> Volets rétractés pour cause de sur-vitesse
You need steel ingots in your inventory to perform this repair.=Vous avez besoin de lingots d'acier pour réaliser cette réparation.
Start/Stop Engines=Démarrer/Arrêter les moteurs
Show/Hide Gauges=Montrer/Cacher les Instruments
Show Inventory=Montrer l'inventaire
Yaw by mouse=Palonnier à la souris
Go Out!=Débarquer !
Flaps down=Volets déployés
Landing Light=Phare d'atterrissage
Autopilot=Autopilote
Co-pilot Manager=Gestionnaire de copilote
Adf Manager=Gestionnaire ADF
Manual=Manuel
Bring a copilot=Embarquer un copilote
Pass the Control=Donner la main
Auto Direction Find=ADF
OK=OK
Change Seat=Échanger les sièges
Go Offboard=Débarquer
Do you really want to go offboard now?=Voulez-vous vraiment débarquer maintenant ?
No=Non
Yes=Oui
>>> There is something wrong with the plane...= >>> Quelque chose est anormal dans cet avion...
>>> ADF deactivated.= >>> ADF désactivé
>>> ADF activated.= >>> ADF activé
>>> Destination written successfully.= >>> Destination enregistrée.
>>> There is something wrong with the ADF fields values.= >>> Quelque chose est anormal dans la configuration de l'ADF.
>>> Both ADF fields must be given to complete the operation.= >>> Les deux informations ADF doivent être fournies pour terminer l'opération.
>>> There is something wrong on ADF saving...= >>> Quelque chose est anormal dans la sauvegarde de l'ADF...
Flight Information=Instruments
>>> You need the priv= >>> Vous devez avoir le privilège
to fly this plane.=pour piloter cet avion.
>>> The engine is damaged, start procedure failed.= >>> Moteur endommagé, Échec du démarrage.
>>> Flap down=Volets déployés
>>> Flap up=Volets relevés
>>> You cannot claim this scrap yet, wait some minutes.= >>> Veuillez attendre quelques minutes pour récupérer ces débris
Sorry, but this module doesn't work when SkinsDb and Armor are instaled together.=Désolé, ce module ne fontionne pas avec les mods SkinDb et Armor
Something isn't working...=Quelque chose défaille...
Set Player Texture=Modifier la texture du joueur
The isn't activated as secure. Aborting=Inactif pour raison de sécurité. Interruption.

Some files were not shown because too many files have changed in this diff Show more