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

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.

View file

@ -0,0 +1,84 @@
# textdomain: airutils
Bio Fuel=Bio Combustível
Biofuel Distiller=Destilador de Bio Combustível
Fuel Distiller=Destilador de Combustível
Fuel Distiller (FULL)=Destilador de Combustível (Cheio)
Fuel Distiller @1% done=Destilador de Combustível @1% concluído
PAPI=PAPI
left side=lado esquerdo
right side=lado direito
Owned by: @1=Pertence à @1
Repair Tool=Ferramente de Reparos
Tug tool for airport=Ferramenta para rebocar aeronaves
@1 is protected by @2.=@1 está protegido por @2.
@1 is protected.=@1 é protegido.
Wind Indicator=Biruta
>>> The wind direction now is @1= >>> A direção do vento agora é @1
Wind Direction Indicator=Indicador de direção de vento
Node is protected=Bloco protegido
Current hp: = Hp atual:
Nice @1 of @2.@3= @1 de @2.@3
>>> The captain got the control.= >>> O controle está com o comandante.
>>> The control is with you now.= >>> O controle está contigo.
>>> The control was given.= >>> Você passou o controle.
Enable/disable explosion blast damage=Ligar/desligar os danos de explosão
>>> Blast damage by explosion is disabled=Danos de explosão desligados.
>>> Blast damage by explosion is enabled=Danos de explosão ligados.
Transfer the property of a plane to another player=Transferir a propriedade da aeronave para outro jogador.
>>> This plane now is property of: = >>> Essa aeronave agora é propriedade de:
>>> only the owner or moderators can transfer this airplane= >>> Apenas o dono ou moderadores podem transferir essa aeronave
>>> the target player must be logged in= >>> O jogador de destino deve estar logado para continuar.
>>> you are not inside a plane to perform the command= >>> você não está na aeronave para executar este comando
Ejects from a plane=Ejetar da aeronave
>>> you are not inside a plane= >>> você não está em uma aeronave
Enables/disables the ground effect (for debug purposes)=Liga/desliga o efeito solo (para debug)
>>> Ground effect was turned on.= >>> Efeito solo ligado.
>>> Ground effect was turned off.=>>> Efeito solo desligado.
>>> You need 'server' priv to run this command.= >>> Você precisa do privilégio 'server' para executar este comando.
Enables/disables the lift printing (for debug purposes)=Liga/desliga o print da sustentação (para debug)
>>> Lift printing turned on.= >>> Print da sustentação ligado.
>>> Lift printing turned off.= >>> Print da sustentação desligado.
>>> Mouse control disabled.= >>> Controle pelo mouse desligado.
>>> Mouse control enabled.= >>> Controle pelo mouse ligado.
>>> Autopilot deactivated= >>> Piloto automático desligado
>>> Autopilot on= >>> Piloto automático ligado
>>> Flaps retracted due for overspeed= >>> Flaps recolhidos devido a alta velocidade
You need steel ingots in your inventory to perform this repair.=Você precisa de lingotes de aço para realizar este reparo.
Start/Stop Engines=Ligar/Desligar motor(es)
Show/Hide Gauges=Exibir/Remover HUD
Show Inventory=Abrir inventário
Yaw by mouse=Direção pelo mouse
Go Out!=Sair da aeronave!
Flaps down=Flaps baixados
Landing Light=Luz de pouso
Autopilot=Piloto automático
Co-pilot Manager=Gerenciar co-piloto
Adf Manager=Gerenciamento de ADF
Manual=Manual
Bring a copilot=Trazer um co-piloto
Pass the Control=Passar o controle
Auto Direction Find=Localiz. Autom. de Direção
OK=OK
Change Seat=Trocar de assento
Go Offboard=Abandonar aeronave
Do you really want to go offboard now?=Tem certeza que deseja sair da aeronave agora?
No=Não
Yes=Sim
>>> There is something wrong with the plane...= >>> Há algo errado com a aeronave...
>>> ADF deactivated.= >>> ADF desativado
>>> ADF activated.= >>> ADF ativado.
>>> Destination written successfully.= >>> Destino gravado com sucesso.
>>> There is something wrong with the ADF fields values.= >>> Há algo errado com os valores do ADF.
>>> Both ADF fields must be given to complete the operation.= >>> Ambos os campos do ADF devem ser preenchidos.
>>> There is something wrong on ADF saving...= >>> Algo deu errado ao salvar os campos do ADF...
Flight Information=Informações de vôo
>>> You need the priv= >>> Você precisa do privilégio
to fly this plane.= para voar esta aeronave.
>>> The engine is damaged, start procedure failed.= >>> Motor danificado, procedimento de partida falhou.
>>> Flap down=>>> Flaps baixados
>>> Flap up=>>> Flaps recolhidos
>>> You cannot claim this scrap yet, wait some minutes.= >>> Você não pode coletar esta sucata ainda, aguarde alguns minutos.
Sorry, but this module doesn't work when SkinsDb and Armor are instaled together.=Desculpe, mas este módulo não funciona quando o SkinsDb e o mod Armor estão instalados juntos.
Something isn't working...=Alguma coisa não está funcionando...
Set Player Texture=Coloque esta textura no jogador
The isn't activated as secure. Aborting=Este mod não está habilitado como seguro, abortando.

View file

@ -0,0 +1,85 @@
# textdomain: airutils
Bio Fuel=Биотопливо
Biofuel Distiller=Дистиллятор биотоплива
Fuel Distiller=Дистиллятор топлива
Fuel Distiller (FULL)=Дистиллятор топлива (ЗАПОЛНЕН)
Fuel Distiller @1% done=Дистиллятор топлива завершен на @1%
PAPI=PAPI
left side=левая сторона
right side=правая сторона
right_side=правая_сторона
Owned by: @1=Принадлежит: @1
Repair Tool=Инструмент для ремонта
Tug tool for airport=Буксировочный инструмент для аэропорта
@1 is protected by @2.=@1 защищен @2.
@1 is protected.=@1 защищен.
Wind Indicator=Индикатор ветра
>>> The wind direction now is @1= >>> Направление воздуха сейчас - это @1
Wind Direction Indicator=Индикатор направления ветра
Node is protected=Нода защищена
Current hp: =Текущий hp:
Nice @1 of @2.@3=Хороши @1 у @2.@3
>>> The captain got the control.= >>> Капитан получил контроль.
>>> The control is with you now.= >>> Теперь вы контролируете.
>>> The control was given.= >>> Контроль был передан.
Enable/disable explosion blast damage=Включить/выключить повреждение от взрыва
>>> Blast damage by explosion is disabled= >>> Выключено повреждение от взрыва
>>> Blast damage by explosion is enabled= >>> Включено повреждение от взрыва
Transfer the property of a plane to another player=Передать владение самолетом другому игроку
>>> This plane now is property of: = >>> Этот самолет теперь принадлежит:
>>> only the owner or moderators can transfer this airplane= >>> только владелец или модераторы могут передать этот самолет
>>> the target player must be logged in= >>> целевой игрок должен быть авторизован
>>> you are not inside a plane to perform the command= >>> вы вне самолета из-за чего не можете выполнить команду
Ejects from a plane=Катапультироваться из самолета
>>> you are not inside a plane= >>> вы вне самолета
Enables/disables the ground effect (for debug purposes)=Включить/выключить эффект приземления (для отладки)
>>> Ground effect was turned on.= >>> Эффект приземления был включен.
>>> Ground effect was turned off.=>>> Эффект приземления выключен.
>>> You need 'server' priv to run this command.= >>> Вам нужна привилегия 'сервер' что бы выполнить эту команду.
Enables/disables the lift printing (for debug purposes)=Печатать о подъеме (для отладки)
>>> Lift printing turned on.= >>> Печатание о подъеме включено.
>>> Lift printing turned off.= >>> Печатание о подъеме выключено.
>>> Mouse control disabled.= >>> Контроль над мышкой выключен.
>>> Mouse control enabled.= >>> Контроль над мышкой включен.
>>> Autopilot deactivated= >>> Автопилот выключен
>>> Autopilot on= >>> Автопилот включен
>>> Flaps retracted due for overspeed= >>> Закрылки убраны из-за превышения скорости
You need steel ingots in your inventory to perform this repair.=Вам нужны железные слитки в вашем инвентаре, что бы починить.
Start/Stop Engines=Включить/выключить двигатели
Show/Hide Gauges=Показать/спрятать датчики
Show Inventory=Показать инвентарь
Yaw by mouse=Рыскание мышью
Go Out!=Выйти!
Flaps down=Закрылки опущены
Landing Light=Посадочный фонарь
Autopilot=Автопилот
Co-pilot Manager=Менеджер второго пилота
Adf Manager=Радиокомпас
Manual=Учебник
Bring a copilot=Привести второго пилота
Pass the Control=Передать управление
Auto Direction Find=Автоматический поиск направления
OK=OK
Change Seat=Сменить сидение
Go Offboard=Выйти за борт
Do you really want to go offboard now?=Вы серьезно хотите выйти за борт?
No=Нет
Yes=Да
>>> There is something wrong with the plane...= >>> Что-то не так с этим самолетом...
>>> ADF deactivated.= >>> Радиокомпас выключен.
>>> ADF activated.= >>> Радиокомпас включен.
>>> Destination written successfully.= >>> Место назначения записано успешно.
>>> There is something wrong with the ADF fields values.= >>> Что-то не так со значениями полей ADF.
>>> Both ADF fields must be given to complete the operation.= >>> Для завершения операции необходимо указать оба поля ADF.
>>> There is something wrong on ADF saving...= >>> Что-то не так с сохранением ADF...
Flight Information=Информация полета
>>> You need the priv= >>> Вам нужна привилегия
to fly this plane.=что бы лететь на этом самолете.
>>> The engine is damaged, start procedure failed.= >>> Двигатель поврежден, запуск провален.
>>> Flap down=>>> Закрылки опущены
>>> Flap up=>>> Закрылки подняты
>>> You cannot claim this scrap yet, wait some minutes.=>>> Вы пока не можете забрать этот лом, подождите несколько минут.
Sorry, but this module doesn't work when SkinsDb and Armor are instaled together.=Извините, но этот модуль не работает, когда SkinsDb и Armor установлены вместе.
Something isn't working...=Что-то не работает...
Set Player Texture=Выберите текстуру игрока
The isn't activated as secure. Aborting=Активация не безопасна. Прерывание

View file

@ -0,0 +1,85 @@
# textdomain: airutils
Bio Fuel=
Biofuel Distiller=
Fuel Distiller=
Fuel Distiller (FULL)=
Fuel Distiller @1% done=
PAPI=
left side=
right side=
right_side=
Owned by: @1=
Repair Tool=
Tug tool for airport=
@1 is protected by @2.=
@1 is protected.=
Wind Indicator=
>>> The wind direction now is @1=
Wind Direction Indicator=
Node is protected=
Current hp: =
Nice @1 of @2.@3=
>>> The captain got the control.=
>>> The control is with you now.=
>>> The control was given.=
Enable/disable explosion blast damage=
>>> Blast damage by explosion is disabled=
>>> Blast damage by explosion is enabled=
Transfer the property of a plane to another player=
>>> This plane now is property of: =
>>> only the owner or moderators can transfer this airplane=
>>> the target player must be logged in=
>>> you are not inside a plane to perform the command=
Ejects from a plane=
>>> you are not inside a plane=
Enables/disables the ground effect (for debug purposes)=
>>> Ground effect was turned on.=
>>> Ground effect was turned off.=
>>> You need 'server' priv to run this command.=
Enables/disables the lift printing (for debug purposes)=
>>> Lift printing turned on.=
>>> Lift printing turned off.=
>>> Mouse control disabled.=
>>> Mouse control enabled.=
>>> Autopilot deactivated=
>>> Autopilot on=
>>> Flaps retracted due for overspeed=
You need steel ingots in your inventory to perform this repair.=
Start/Stop Engines=
Show/Hide Gauges=
Show Inventory=
Yaw by mouse=
Go Out!=
Flaps down=
Landing Light=
Autopilot=
Co-pilot Manager=
Adf Manager=
Manual=
Bring a copilot=
Pass the Control=
Auto Direction Find=
OK=
Change Seat=
Go Offboard=
Do you really want to go offboard now?=
No=
Yes=
>>> There is something wrong with the plane...=
>>> ADF deactivated.=
>>> ADF activated.=
>>> Destination written successfully.=
>>> There is something wrong with the ADF fields values.=
>>> Both ADF fields must be given to complete the operation.=
>>> There is something wrong on ADF saving...=
Flight Information=
>>> You need the priv=
to fly this plane.=
>>> The engine is damaged, start procedure failed.=
>>> Flap down=
>>> Flap up=
>>> You cannot claim this scrap yet, wait some minutes.=
Sorry, but this module doesn't work when SkinsDb and Armor are instaled together.=
Something isn't working...=
Set Player Texture=
The isn't activated as secure. Aborting=

6
mods/airutils/mod.conf Normal file
View file

@ -0,0 +1,6 @@
name = airutils
title=AirUtils
description=A lib for airplanes and some useful tools
author=apercy
optional_depends=player_api, mcl_formspec, mcl_player, emote, climate_api, biofuel, signs_lib, skinsdb
release = 31048

View file

@ -0,0 +1,495 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Script to generate Minetest translation template files and update
# translation files.
#
# Copyright (C) 2019 Joachim Stolberg, 2020 FaceDeer, 2020 Louis Royer,
# 2023 Wuzzy.
# License: LGPLv2.1 or later (see LICENSE file for details)
import os, fnmatch, re, shutil, errno
from sys import argv as _argv
from sys import stderr as _stderr
# Running params
params = {"recursive": False,
"help": False,
"verbose": False,
"folders": [],
"old-file": False,
"break-long-lines": False,
"print-source": False,
"truncate-unused": False,
}
# Available CLI options
options = {"recursive": ['--recursive', '-r'],
"help": ['--help', '-h'],
"verbose": ['--verbose', '-v'],
"old-file": ['--old-file', '-o'],
"break-long-lines": ['--break-long-lines', '-b'],
"print-source": ['--print-source', '-p'],
"truncate-unused": ['--truncate-unused', '-t'],
}
# Strings longer than this will have extra space added between
# them in the translation files to make it easier to distinguish their
# beginnings and endings at a glance
doublespace_threshold = 80
# These symbols mark comment lines showing the source file name.
# A comment may look like "##[ init.lua ]##".
symbol_source_prefix = "##["
symbol_source_suffix = "]##"
# comment to mark the section of old/unused strings
comment_unused = "##### not used anymore #####"
def set_params_folders(tab: list):
'''Initialize params["folders"] from CLI arguments.'''
# Discarding argument 0 (tool name)
for param in tab[1:]:
stop_param = False
for option in options:
if param in options[option]:
stop_param = True
break
if not stop_param:
params["folders"].append(os.path.abspath(param))
def set_params(tab: list):
'''Initialize params from CLI arguments.'''
for option in options:
for option_name in options[option]:
if option_name in tab:
params[option] = True
break
def print_help(name):
'''Prints some help message.'''
print(f'''SYNOPSIS
{name} [OPTIONS] [PATHS...]
DESCRIPTION
{', '.join(options["help"])}
prints this help message
{', '.join(options["recursive"])}
run on all subfolders of paths given
{', '.join(options["old-file"])}
create *.old files
{', '.join(options["break-long-lines"])}
add extra line breaks before and after long strings
{', '.join(options["print-source"])}
add comments denoting the source file
{', '.join(options["verbose"])}
add output information
{', '.join(options["truncate-unused"])}
delete unused strings from files
''')
def main():
'''Main function'''
set_params(_argv)
set_params_folders(_argv)
if params["help"]:
print_help(_argv[0])
else:
# Add recursivity message
print("Running ", end='')
if params["recursive"]:
print("recursively ", end='')
# Running
if len(params["folders"]) >= 2:
print("on folder list:", params["folders"])
for f in params["folders"]:
if params["recursive"]:
run_all_subfolders(f)
else:
update_folder(f)
elif len(params["folders"]) == 1:
print("on folder", params["folders"][0])
if params["recursive"]:
run_all_subfolders(params["folders"][0])
else:
update_folder(params["folders"][0])
else:
print("on folder", os.path.abspath("./"))
if params["recursive"]:
run_all_subfolders(os.path.abspath("./"))
else:
update_folder(os.path.abspath("./"))
# Group 2 will be the string, groups 1 and 3 will be the delimiters (" or ')
# See https://stackoverflow.com/questions/46967465/regex-match-text-in-either-single-or-double-quote
pattern_lua_quoted = re.compile(
r'(?:^|[\.=,{\(\s])' # Look for beginning of file or anything that isn't a function identifier
r'N?F?S\s*\(\s*' # Matches S, FS, NS or NFS function call
r'(["\'])((?:\\\1|(?:(?!\1)).)*)(\1)' # Quoted string
r'[\s,\)]', # End of call or argument
re.DOTALL)
# Handles the [[ ... ]] string delimiters
pattern_lua_bracketed = re.compile(
r'(?:^|[\.=,{\(\s])' # Same as for pattern_lua_quoted
r'N?F?S\s*\(\s*' # Same as for pattern_lua_quoted
r'\[\[(.*?)\]\]' # [[ ... ]] string delimiters
r'[\s,\)]', # Same as for pattern_lua_quoted
re.DOTALL)
# Handles "concatenation" .. " of strings"
pattern_concat = re.compile(r'["\'][\s]*\.\.[\s]*["\']', re.DOTALL)
# Handles a translation line in *.tr file.
# Group 1 is the source string left of the equals sign.
# Group 2 is the translated string, right of the equals sign.
pattern_tr = re.compile(
r'(.*)' # Source string
# the separating equals sign, if NOT preceded by @, unless
# that @ is preceded by another @
r'(?:(?<!(?<!@)@)=)'
r'(.*)' # Translation string
)
pattern_name = re.compile(r'^name[ ]*=[ ]*([^ \n]*)')
pattern_tr_filename = re.compile(r'\.tr$')
# Matches bad use of @ signs in Lua string
pattern_bad_luastring = re.compile(
r'^@$|' # single @, OR
r'[^@]@$|' # trailing unescaped @, OR
r'(?<!@)@(?=[^@1-9])' # an @ that is not escaped or part of a placeholder
)
# Attempt to read the mod's name from the mod.conf file or folder name. Returns None on failure
def get_modname(folder):
try:
with open(os.path.join(folder, "mod.conf"), "r", encoding='utf-8') as mod_conf:
for line in mod_conf:
match = pattern_name.match(line)
if match:
return match.group(1)
except FileNotFoundError:
if not os.path.isfile(os.path.join(folder, "modpack.txt")):
folder_name = os.path.basename(folder)
# Special case when run in Minetest's builtin directory
if folder_name == "builtin":
return "__builtin"
else:
return folder_name
else:
return None
return None
# If there are already .tr files in /locale, returns a list of their names
def get_existing_tr_files(folder):
out = []
for root, dirs, files in os.walk(os.path.join(folder, 'locale/')):
for name in files:
if pattern_tr_filename.search(name):
out.append(name)
return out
# from https://stackoverflow.com/questions/600268/mkdir-p-functionality-in-python/600612#600612
# Creates a directory if it doesn't exist, silently does
# nothing if it already exists
def mkdir_p(path):
try:
os.makedirs(path)
except OSError as exc: # Python >2.5
if exc.errno == errno.EEXIST and os.path.isdir(path):
pass
else: raise
# Converts the template dictionary to a text to be written as a file
# dKeyStrings is a dictionary of localized string to source file sets
# dOld is a dictionary of existing translations and comments from
# the previous version of this text
def strings_to_text(dkeyStrings, dOld, mod_name, header_comments, textdomain):
# if textdomain is specified, insert it at the top
if textdomain != None:
lOut = [textdomain] # argument is full textdomain line
# otherwise, use mod name as textdomain automatically
else:
lOut = [f"# textdomain: {mod_name}"]
if header_comments is not None:
lOut.append(header_comments)
dGroupedBySource = {}
for key in dkeyStrings:
sourceList = list(dkeyStrings[key])
sourceString = "\n".join(sourceList)
listForSource = dGroupedBySource.get(sourceString, [])
listForSource.append(key)
dGroupedBySource[sourceString] = listForSource
lSourceKeys = list(dGroupedBySource.keys())
lSourceKeys.sort()
for source in lSourceKeys:
localizedStrings = dGroupedBySource[source]
if params["print-source"]:
if lOut[-1] != "":
lOut.append("")
lOut.append(source)
for localizedString in localizedStrings:
val = dOld.get(localizedString, {})
translation = val.get("translation", "")
comment = val.get("comment")
if params["break-long-lines"] and len(localizedString) > doublespace_threshold and not lOut[-1] == "":
lOut.append("")
if comment != None and comment != "" and not comment.startswith("# textdomain:"):
lOut.append(comment)
lOut.append(f"{localizedString}={translation}")
if params["break-long-lines"] and len(localizedString) > doublespace_threshold:
lOut.append("")
unusedExist = False
if not params["truncate-unused"]:
for key in dOld:
if key not in dkeyStrings:
val = dOld[key]
translation = val.get("translation")
comment = val.get("comment")
# only keep an unused translation if there was translated
# text or a comment associated with it
if translation != None and (translation != "" or comment):
if not unusedExist:
unusedExist = True
lOut.append("\n\n" + comment_unused + "\n")
if params["break-long-lines"] and len(key) > doublespace_threshold and not lOut[-1] == "":
lOut.append("")
if comment != None:
lOut.append(comment)
lOut.append(f"{key}={translation}")
if params["break-long-lines"] and len(key) > doublespace_threshold:
lOut.append("")
return "\n".join(lOut) + '\n'
# Writes a template.txt file
# dkeyStrings is the dictionary returned by generate_template
def write_template(templ_file, dkeyStrings, mod_name):
# read existing template file to preserve comments
existing_template = import_tr_file(templ_file)
text = strings_to_text(dkeyStrings, existing_template[0], mod_name, existing_template[2], existing_template[3])
mkdir_p(os.path.dirname(templ_file))
with open(templ_file, "wt", encoding='utf-8') as template_file:
template_file.write(text)
# Gets all translatable strings from a lua file
def read_lua_file_strings(lua_file):
lOut = []
with open(lua_file, encoding='utf-8') as text_file:
text = text_file.read()
text = re.sub(pattern_concat, "", text)
strings = []
for s in pattern_lua_quoted.findall(text):
strings.append(s[1])
for s in pattern_lua_bracketed.findall(text):
strings.append(s)
for s in strings:
found_bad = pattern_bad_luastring.search(s)
if found_bad:
print("SYNTAX ERROR: Unescaped '@' in Lua string: " + s)
continue
s = s.replace('\\"', '"')
s = s.replace("\\'", "'")
s = s.replace("\n", "@n")
s = s.replace("\\n", "@n")
s = s.replace("=", "@=")
lOut.append(s)
return lOut
# Gets strings from an existing translation file
# returns both a dictionary of translations
# and the full original source text so that the new text
# can be compared to it for changes.
# Returns also header comments in the third return value.
def import_tr_file(tr_file):
dOut = {}
text = None
in_header = True
header_comments = None
textdomain = None
if os.path.exists(tr_file):
with open(tr_file, "r", encoding='utf-8') as existing_file :
# save the full text to allow for comparison
# of the old version with the new output
text = existing_file.read()
existing_file.seek(0)
# a running record of the current comment block
# we're inside, to allow preceeding multi-line comments
# to be retained for a translation line
latest_comment_block = None
for line in existing_file.readlines():
line = line.rstrip('\n')
# "##### not used anymore #####" comment
if line == comment_unused:
# Always delete the 'not used anymore' comment.
# It will be re-added to the file if neccessary.
latest_comment_block = None
if header_comments != None:
in_header = False
continue
# Comment lines
elif line.startswith("#"):
# Source file comments: ##[ file.lua ]##
if line.startswith(symbol_source_prefix) and line.endswith(symbol_source_suffix):
# This line marks the end of header comments.
if params["print-source"]:
in_header = False
# Remove those comments; they may be added back automatically.
continue
# Store first occurance of textdomain
# discard all subsequent textdomain lines
if line.startswith("# textdomain:"):
if textdomain == None:
textdomain = line
continue
elif in_header:
# Save header comments (normal comments at top of file)
if not header_comments:
header_comments = line
else:
header_comments = header_comments + "\n" + line
else:
# Save normal comments
if line.startswith("# textdomain:") and textdomain == None:
textdomain = line
elif not latest_comment_block:
latest_comment_block = line
else:
latest_comment_block = latest_comment_block + "\n" + line
continue
match = pattern_tr.match(line)
if match:
# this line is a translated line
outval = {}
outval["translation"] = match.group(2)
if latest_comment_block:
# if there was a comment, record that.
outval["comment"] = latest_comment_block
latest_comment_block = None
in_header = False
dOut[match.group(1)] = outval
return (dOut, text, header_comments, textdomain)
# like os.walk but returns sorted filenames
def sorted_os_walk(folder):
tuples = []
t = 0
for root, dirs, files in os.walk(folder):
tuples.append( (root, dirs, files) )
t = t + 1
tuples = sorted(tuples)
paths_and_files = []
f = 0
for tu in tuples:
root = tu[0]
dirs = tu[1]
files = tu[2]
files = sorted(files, key=str.lower)
for filename in files:
paths_and_files.append( (os.path.join(root, filename), filename) )
f = f + 1
return paths_and_files
# Walks all lua files in the mod folder, collects translatable strings,
# and writes it to a template.txt file
# Returns a dictionary of localized strings to source file lists
# that can be used with the strings_to_text function.
def generate_template(folder, mod_name):
dOut = {}
paths_and_files = sorted_os_walk(folder)
for paf in paths_and_files:
fullpath_filename = paf[0]
filename = paf[1]
if fnmatch.fnmatch(filename, "*.lua"):
found = read_lua_file_strings(fullpath_filename)
if params["verbose"]:
print(f"{fullpath_filename}: {str(len(found))} translatable strings")
for s in found:
sources = dOut.get(s, set())
sources.add(os.path.relpath(fullpath_filename, start=folder))
dOut[s] = sources
if len(dOut) == 0:
return None
# Convert source file set to list, sort it and add comment symbols.
# Needed because a set is unsorted and might result in unpredictable.
# output orders if any source string appears in multiple files.
for d in dOut:
sources = dOut.get(d, set())
sources = sorted(list(sources), key=str.lower)
newSources = []
for i in sources:
newSources.append(f"{symbol_source_prefix} {i} {symbol_source_suffix}")
dOut[d] = newSources
templ_file = os.path.join(folder, "locale/template.txt")
write_template(templ_file, dOut, mod_name)
return dOut
# Updates an existing .tr file, copying the old one to a ".old" file
# if any changes have happened
# dNew is the data used to generate the template, it has all the
# currently-existing localized strings
def update_tr_file(dNew, mod_name, tr_file):
if params["verbose"]:
print(f"updating {tr_file}")
tr_import = import_tr_file(tr_file)
dOld = tr_import[0]
textOld = tr_import[1]
textNew = strings_to_text(dNew, dOld, mod_name, tr_import[2], tr_import[3])
if textOld and textOld != textNew:
print(f"{tr_file} has changed.")
if params["old-file"]:
shutil.copyfile(tr_file, f"{tr_file}.old")
with open(tr_file, "w", encoding='utf-8') as new_tr_file:
new_tr_file.write(textNew)
# Updates translation files for the mod in the given folder
def update_mod(folder):
modname = get_modname(folder)
if modname is not None:
print(f"Updating translations for {modname}")
data = generate_template(folder, modname)
if data == None:
print(f"No translatable strings found in {modname}")
else:
for tr_file in get_existing_tr_files(folder):
update_tr_file(data, modname, os.path.join(folder, "locale/", tr_file))
else:
print(f"Unable to determine the mod name in folder {folder}. Missing 'name' field in mod.conf.", file=_stderr)
exit(1)
# Determines if the folder being pointed to is a mod or a mod pack
# and then runs update_mod accordingly
def update_folder(folder):
is_modpack = os.path.exists(os.path.join(folder, "modpack.txt")) or os.path.exists(os.path.join(folder, "modpack.conf"))
if is_modpack:
subfolders = [f.path for f in os.scandir(folder) if f.is_dir() and not f.name.startswith('.')]
for subfolder in subfolders:
update_mod(subfolder)
else:
update_mod(folder)
print("Done.")
def run_all_subfolders(folder):
for modfolder in [f.path for f in os.scandir(folder) if f.is_dir() and not f.name.startswith('.')]:
update_folder(modfolder)
main()

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,182 @@
airutils.gravity = -9.8
local abs = math.abs
local pi = math.pi
local floor = math.floor
local ceil = math.ceil
local random = math.random
local sqrt = math.sqrt
local max = math.max
local min = math.min
local tan = math.tan
local pow = math.pow
local sign = function(x)
return (x<0) and -1 or 1
end
function airutils.rot_to_dir(rot) -- keep rot within <-pi/2,pi/2>
local dir = minetest.yaw_to_dir(rot.y)
dir.y = dir.y+tan(rot.x)*vector.length(dir)
return vector.normalize(dir)
end
function airutils.dir_to_rot(v,rot)
rot = rot or {x=0,y=0,z=0}
return {x = (v.x==0 and v.y==0 and v.z==0) and rot.x or math.atan2(v.y,vector.length({x=v.x,y=0,z=v.z})),
y = (v.x==0 and v.z==0) and rot.y or minetest.dir_to_yaw(v),
z=rot.z}
end
function airutils.pos_shift(pos,vec) -- vec components can be omitted e.g. vec={y=1}
vec.x=vec.x or 0
vec.y=vec.y or 0
vec.z=vec.z or 0
return {x=pos.x+vec.x,
y=pos.y+vec.y,
z=pos.z+vec.z}
end
function airutils.get_stand_pos(thing) -- thing can be luaentity or objectref.
local pos = {}
local colbox = {}
if type(thing) == 'table' then
pos = thing.object:get_pos()
if not thing.object:get_properties() then return false end
colbox = thing.object:get_properties().collisionbox
elseif type(thing) == 'userdata' then
pos = thing:get_pos()
if not thing:get_properties() then return false end
colbox = thing:get_properties().collisionbox
else
return false
end
return airutils.pos_shift(pos,{y=colbox[2]+0.01}), pos
end
function airutils.get_node_pos(pos)
return {
x=floor(pos.x+0.5),
y=floor(pos.y+0.5),
z=floor(pos.z+0.5),
}
end
function airutils.nodeatpos(pos)
if pos == nil then return end
local node = minetest.get_node_or_nil(pos)
if node then return minetest.registered_nodes[node.name] end
end
function airutils.minmax(v,m)
return min(abs(v),m)*sign(v)
end
function airutils.set_acceleration(thing,vec,limit)
limit = limit or 100
if type(thing) == 'table' then thing=thing.object end
vec.x=airutils.minmax(vec.x,limit)
vec.y=airutils.minmax(vec.y,limit)
vec.z=airutils.minmax(vec.z,limit)
thing:set_acceleration(vec)
end
function airutils.actfunc(self, staticdata, dtime_s)
self.logic = self.logic or self.brainfunc
self.physics = self.physics or airutils.physics
self.lqueue = {}
self.hqueue = {}
self.nearby_objects = {}
self.nearby_players = {}
self.pos_history = {}
self.path_dir = 1
self.time_total = 0
self.water_drag = self.water_drag or 1
local sdata = minetest.deserialize(staticdata)
if sdata then
for k,v in pairs(sdata) do
self[k] = v
end
end
if self.textures==nil then
local prop_tex = self.object:get_properties().textures
if prop_tex then self.textures=prop_tex end
end
if not self.memory then -- this is the initial activation
self.memory = {}
-- texture variation
if #self.textures > 1 then self.texture_no = random(#self.textures) end
end
if self.timeout and ((self.timeout>0 and dtime_s > self.timeout and next(self.memory)==nil) or
(self.timeout<0 and dtime_s > abs(self.timeout))) then
self.object:remove()
end
-- apply texture
if self.textures and self.texture_no then
local props = {}
props.textures = {self.textures[self.texture_no]}
self.object:set_properties(props)
end
--hp
self.max_hp = self.max_hp or 10
self.hp = self.hp or self.max_hp
--armor
if type(self.armor_groups) ~= 'table' then
self.armor_groups={}
end
self.armor_groups.immortal = 1
self.object:set_armor_groups(self.armor_groups)
self.buoyancy = self.buoyancy or 0
self.oxygen = self.oxygen or self.lung_capacity
self.lastvelocity = {x=0,y=0,z=0}
end
function airutils.get_box_height(self)
if type(self) == 'table' then self = self.object end
local colbox = self:get_properties().collisionbox
local height = 0.1
if colbox then height = colbox[5]-colbox[2] end
return height > 0 and height or 0.1
end
function airutils.stepfunc(self,dtime,colinfo)
self.dtime = min(dtime,0.2)
self.colinfo = colinfo
self.height = airutils.get_box_height(self)
-- physics comes first
local vel = self.object:get_velocity()
if colinfo then
self.isonground = colinfo.touching_ground
else
if self.lastvelocity.y==0 and vel.y==0 then
self.isonground = true
else
self.isonground = false
end
end
self:physics()
if self.logic then
if self.view_range then self:sensefunc() end
self:logic()
--execute_queues(self)
end
self.lastvelocity = self.object:get_velocity()
self.time_total=self.time_total+self.dtime
end

View file

@ -0,0 +1,168 @@
local S = airutils.S
airutils.pilot_textures = {"pilot_clothes1.png","pilot_clothes2.png","pilot_clothes3.png","pilot_clothes4.png",
"pilot_novaskin_girl.png","pilot_novaskin_girl_steampunk.png","pilot_novaskin_girl_2.png","pilot_novaskin_girl_steampunk_2.png"}
local skinsdb_mod_path = minetest.get_modpath("skinsdb")
minetest.register_chatcommand("au_uniform", {
func = function(name, param)
local player = minetest.get_player_by_name(name)
if player then
if skinsdb_mod_path then
local skdb_skin = skins.get_player_skin(player)
if skdb_skin:get_meta("format") == "1.8" then
minetest.chat_send_player(name, S("Sorry, but uniform cannot be applied to format 1.8 skins."))
return
end
end
airutils.uniform_formspec(name)
else
minetest.chat_send_player(name, S("Something isn't working..."))
end
end,
})
local set_player_textures =
minetest.get_modpath("player_api") and player_api.set_textures
or default.player_set_textures
if skinsdb_mod_path then
-- Enhance apply_skin_to_player for all skins
local orig_apply_skin_to_player = skins.skin_class.apply_skin_to_player
function skins.skin_class:apply_skin_to_player(player)
local orig_texture = self:get_texture()
local player_meta = player:get_meta()
local pilot_skin = player_meta:get_string("pilot_skin")
if pilot_skin ~= "" then
if self:get_meta("format") == "1.8" then
-- format 1.8 is not suported
orig_apply_skin_to_player(self, player)
else
local orig_get_texture = self.get_texture
function self:get_texture()
return "[combine:64x32:0,0="..orig_texture.."^"..pilot_skin
end
orig_apply_skin_to_player(self, player)
self.get_texture = orig_get_texture
end
else
orig_apply_skin_to_player(self, player)
end
end
end
function airutils.set_player_skin(player, skin)
if not player then return end
-- use skinsdb enhancement
if skinsdb_mod_path then
local player_meta = player:get_meta()
player_meta:set_string("pilot_skin", skin)
local skdb_skin = skins.get_player_skin(player)
skdb_skin:apply_skin_to_player(player)
return
end
-- manage byself
local player_properties = player:get_properties()
if not player_properties then return end
local texture = player_properties.textures
local name = player:get_player_name()
if texture then
local player_meta = player:get_meta()
if skin then
--get current texture
texture = texture[1]
--backup current texture
local backup = player_meta:get_string("backup")
if backup == nil or backup == "" then
--player:set_attribute(backup, texture) --texture backup
player_meta:set_string("backup",texture)
else
texture = backup
end
--combine the texture
texture = texture.."^"..skin
--sets the combined texture
if texture ~= nil and texture ~= "" then
set_player_textures(player, {texture})
player_meta:set_string("curr_skin",texture)
--player:set_attribute(curr_skin, texture)
end
else
--remove texture
local old_texture = player_meta:get_string("backup")
if minetest.global_exists("set_skin") then --checking if set_skin is available
if player:get_attribute("set_skin:player_skin") ~= nil and player:get_attribute("set_skin:player_skin") ~= "" then
old_texture = player:get_attribute("set_skin:player_skin")
end
elseif minetest.global_exists("wardrobe") then --checking if wardrobe is available
if wardrobe.playerSkins then
if wardrobe.playerSkins[name] ~= nil then
old_texture = wardrobe.playerSkins[name]
end
end
end
--minetest.chat_send_all(dump(old_texture))
if old_texture ~= nil and old_texture ~= "" then
set_player_textures(player, { old_texture })
end
player_meta:set_string("backup","")
player_meta:set_string("curr_skin","")
--player:set_attribute(backup, nil)
--player:set_attribute(curr_skin, nil)
end
end
end
function airutils.uniform_formspec(name)
local basic_form = table.concat({
"formspec_version[5]",
"size[5,2.9]",
}, "")
--minetest.chat_send_all(dump(airutils.pilot_textures))
local textures = ""
if airutils.pilot_textures then
for k, v in pairs( airutils.pilot_textures ) do
textures = textures .. v .. ","
end
basic_form = basic_form.."dropdown[0.5,0.5;4,0.8;textures;".. textures ..";0;false]"
basic_form = basic_form.."button[0.5,1.6;4,0.8;set_texture;" .. S("Set Player Texture") .. "]"
minetest.show_formspec(name, "airutils:change", basic_form)
else
minetest.chat_send_player(name, S("The isn't activated as secure. Aborting"))
end
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname == "airutils:change" then
local name = player:get_player_name()
if fields.textures or fields.set_texture then
airutils.set_player_skin(player, fields.textures)
end
minetest.close_formspec(name, "airutils:change")
end
end)
minetest.register_on_joinplayer(function(player)
local player_meta = player:get_meta()
local skin = player_meta:get_string("curr_skin")
--minetest.chat_send_all(">>>"..skin)
if skin and skin ~= "" and skin ~= nil then
-- setting player skin on connect has no effect, so delay skin change
minetest.after(3, function(player1, skin1)
airutils.set_player_skin(player1, skin1)
end, player, skin)
end
end)

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

View file

@ -0,0 +1,24 @@
# all settings for client menu or in minetest.conf on servers
# protect airplanes from player damage in protected areas
airutils_protect_in_areas (protect in area) bool true
# disable PAPI (Precision Approach Path Indicator)
airutils_disable_papi (disable PAPI) bool false
# disable tug tool (reposition of not owning planes)
airutils_disable_tug (disable tug tool) bool false
# disable repair tool for planes
airutils_disable_repair (planes cannot be repaired) bool false
# enable debug od activation and deactivation of the vehicle entity
airutils_debug_log (log of entity activation) bool false
# disable the usage of signs_api by the vehicles
airutils_disable_signs_api (no names writen on vehicles surface) bool false
# enable water particles effect
airutils_enable_water_particles (enable particles on water) bool false

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,5 @@
airutils_heli_snd.ogg
remixed from
https://freesound.org/people/Carlfnf/sounds/700861/
Author Carlfnf
Licence CC0

Binary file not shown.

Binary file not shown.

280
mods/airutils/text.lua Normal file
View file

@ -0,0 +1,280 @@
--[[
License for code: LGPL 3.0
see at: https://www.gnu.org/licenses/lgpl-3.0.txt
This code was adapted from signs_lib from VanessaE
the original lib can be found at: https://content.minetest.net/packages/mt-mods/signs_lib/
]]--
-- CONSTANTS
-- Path to the textures.
local TP = signs_lib.path .. "/textures"
-- Font file formatter
local CHAR_FILE = "%s_%02x.png"
-- Fonts path
local CHAR_PATH = TP .. "/" .. CHAR_FILE
local max_lenght = 20
-- Initialize character texture cache
local ctexcache = {}
local function fill_line(x, y, w, c, font_size, colorbgw)
c = c or "0"
local tex = { }
for xx = 0, math.max(0, w), colorbgw do
table.insert(tex, (":%d,%d=signs_lib_color_"..font_size.."px_%s.png"):format(x + xx, y, c))
end
return table.concat(tex)
end
local function clamp_characters(text, max_lenght)
text = text or ""
max_lenght = max_lenght or 20
local control_chars = {"##","#0","#1","#2","#3","#4","#5","#6","#7","#8","#9","#a","#b","#c","#d","#e","#f"}
local control_order = {}
local new_string = text
--first creates a memory of each control code
for i = 1, #new_string do
local c = new_string:sub(i,i+1)
for i, item in pairs(control_chars) do
if c == item then
table.insert(control_order, item)
break
end
end
end
--create control spaces (the order was saved in "control_order"
local control_char = "\001"
for i, item in pairs(control_chars) do
new_string = string.gsub(new_string, item, control_char)
end
--now make another string counting it outside and breaking when reachs 20
local count = 0
local curr_index = 0
local c = ""
for i = 1, #new_string, 1 do
c = string.sub(new_string,i,i)
if c ~= control_char then
count = count + 1
end
curr_index = i
if count == max_lenght then break end
end
local cutstring = string.sub(new_string,1,curr_index)
--now reconstruct the string
local outputstring = ""
local control_order_curr_intex = 0
for i = 1, #cutstring, 1 do
c = string.sub(cutstring,i,i)
if c ~= control_char then
outputstring = outputstring .. (c or "")
else
control_order_curr_intex = control_order_curr_intex + 1
outputstring = outputstring .. (control_order[control_order_curr_intex] or "")
end
end
return outputstring, count
end
-- check if a file does exist
-- to avoid reopening file after checking again
-- pass TRUE as second argument
local function file_exists(name, return_handle, mode)
mode = mode or "r";
local f = io.open(name, mode)
if f ~= nil then
if (return_handle) then
return f
end
io.close(f)
return true
else
return false
end
end
-- make char texture file name
-- if texture file does not exist use fallback texture instead
local function char_tex(font_name, ch)
if ctexcache[font_name..ch] then
return ctexcache[font_name..ch], true
else
local c = ch:byte()
local exists, tex = file_exists(CHAR_PATH:format(font_name, c))
if exists and c ~= 14 then
tex = CHAR_FILE:format(font_name, c)
else
tex = CHAR_FILE:format(font_name, 0x0)
end
ctexcache[font_name..ch] = tex
return tex, exists
end
end
local function make_text_texture(text, default_color, line_width, line_height, cwidth_tab, font_size, colorbgw)
local split = signs_lib.split_lines_and_words
local width = 0
local maxw = 0
local font_name = "signs_lib_font_"..font_size.."px"
local text_ansi = signs_lib.Utf8ToAnsi(text)
local text_splited = split(text_ansi)[1]
local words = { }
default_color = default_color or 0
local cur_color = tonumber(default_color, 16)
-- We check which chars are available here.
for word_i, word in ipairs(text_splited) do
local chars = { }
local ch_offs = 0
word = string.gsub(word, "%^[12345678abcdefgh]", {
["^1"] = string.char(0x81),
["^2"] = string.char(0x82),
["^3"] = string.char(0x83),
["^4"] = string.char(0x84),
["^5"] = string.char(0x85),
["^6"] = string.char(0x86),
["^7"] = string.char(0x87),
["^8"] = string.char(0x88),
["^a"] = string.char(0x8a),
["^b"] = string.char(0x8b),
["^c"] = string.char(0x8c),
["^d"] = string.char(0x8d),
["^e"] = string.char(0x8e),
["^f"] = string.char(0x8f),
["^g"] = string.char(0x90),
["^h"] = string.char(0x91)
})
local word_l = #word
local i = 1
while i <= word_l do
local c = word:sub(i, i)
if c == "#" then
local cc = tonumber(word:sub(i+1, i+1), 16)
if cc then
i = i + 1
cur_color = cc
end
else
local w = cwidth_tab[c]
if w then
width = width + w + 1
if width >= (line_width - cwidth_tab[" "]) then
width = 0
else
maxw = math.max(width, maxw)
end
local max_input_chars = max_lenght
if #chars < max_input_chars then
table.insert(chars, {
off = ch_offs,
tex = char_tex(font_name, c),
col = ("%X"):format(cur_color),
})
end
ch_offs = ch_offs + w
end
end
i = i + 1
end
width = width + cwidth_tab[" "] + 1
maxw = math.max(width, maxw)
table.insert(words, { chars=chars, w=ch_offs })
end
-- Okay, we actually build the "line texture" here.
local texture = { }
local start_xpos = math.floor((line_width - maxw) / 2)
local xpos = start_xpos
local ypos = line_height
if line_height == signs_lib.lineheight32 then ypos = line_height/4 end
cur_color = nil
for word_i, word in ipairs(words) do
local xoffs = (xpos - start_xpos)
if (xoffs > 0) and ((xoffs + word.w) > maxw) then
table.insert(texture, fill_line(xpos, ypos, maxw, "n", font_size, colorbgw))
xpos = start_xpos
ypos = ypos + line_height
table.insert(texture, fill_line(xpos, ypos, maxw, cur_color, font_size, colorbgw))
end
for ch_i, ch in ipairs(word.chars) do
if ch.col ~= cur_color then
cur_color = ch.col
table.insert(texture, fill_line(xpos + ch.off, ypos, maxw, cur_color, font_size, colorbgw))
end
table.insert(texture, (":%d,%d=%s"):format(xpos + ch.off, ypos, ch.tex))
end
table.insert(
texture,
(":%d,%d="):format(xpos + word.w, ypos) .. char_tex(font_name, " ")
)
xpos = xpos + word.w + cwidth_tab[" "]
if xpos >= (line_width + cwidth_tab[" "]) then break end
end
table.insert(texture, fill_line(xpos, ypos, maxw, "n", font_size, colorbgw))
table.insert(texture, fill_line(start_xpos, ypos + line_height, maxw, "n", font_size, colorbgw))
return table.concat(texture)
end
function airutils.convert_text_to_texture(text, default_color, horizontal_aligment)
text = text or ""
default_color = default_color or 0
horizontal_aligment = horizontal_aligment or 3
if not signs_lib then return "" end
local font_size = 16
local line_width = 1
local line_height = 1
local char_width = 1
local colorbgw = ""
local chars_per_line = 21
local widemult = 0.5
local count = 0
--text = string.sub(text,1,max_lenght)
text, count = clamp_characters(text, max_lenght)
if count <= 10 then
if signs_lib.avgwidth32 then
widemult = 0.75
font_size = 32
chars_per_line = 10
line_width = math.floor(signs_lib.avgwidth32 * chars_per_line) * (horizontal_aligment * widemult)
line_height = signs_lib.lineheight32
char_width = signs_lib.charwidth32
colorbgw = signs_lib.colorbgw32
else
return ""
end
else
if signs_lib.avgwidth16 then
widemult = 0.5
font_size = 16
chars_per_line = 21
line_width = math.floor(signs_lib.avgwidth16 * chars_per_line) * (horizontal_aligment * widemult)
line_height = signs_lib.lineheight16
char_width = signs_lib.charwidth16
colorbgw = signs_lib.colorbgw16
else
return ""
end
end
local texture = { ("[combine:%dx%d"):format(line_width, line_height) }
local linetex = make_text_texture(text, default_color, line_width, line_height, char_width, font_size, colorbgw)
table.insert(texture, linetex)
table.insert(texture, "^[makealpha:0,0,0")
return table.concat(texture, "")
end

View file

@ -0,0 +1,137 @@
-- Function to extract textures from a node definition
local function getTexturesFromNode(node)
local textures = {}
if node.tiles then
if type(node.tiles) == "string" then
table.insert(textures, node.tiles)
elseif type(node.tiles) == "table" then
for _, tile in pairs(node.tiles) do
if type(tile) == "string" then
table.insert(textures, tile)
end
end
end
end
return textures
end
-- Function to extract textures from an entity definition
local function getTexturesFromEntity(entityDef)
local textures = {}
if entityDef.textures then
if type(entityDef.textures) == "string" then
table.insert(textures, entityDef.textures)
elseif type(entityDef.textures) == "table" then
for _, texture in pairs(entityDef.textures) do
if type(texture) == "string" then
table.insert(textures, texture)
end
end
end
end
return textures
end
-- Function to extract textures from an item definition
local function getTexturesFromItem(itemDef)
local textures = {}
if itemDef.inventory_image then
table.insert(textures, itemDef.inventory_image)
end
return textures
end
--function to remove duplicates and invalid for textlist
local function filter_texture_names(list_to_test)
local hash = {}
local result = {}
for _,v in ipairs(list_to_test) do
if not string.find(v, ",") then
if (not hash[v]) then
result[#result+1] = v
hash[v] = true
end
end
end
return result
end
-- Function to list all loaded textures
local function listLoadedTextures()
local loadedTextures = {}
--nodes
for name, node in pairs(minetest.registered_nodes) do
local textures = getTexturesFromNode(node)
for _, texture in pairs(textures) do
table.insert(loadedTextures, texture)
end
end
airutils.all_game_textures = filter_texture_names(loadedTextures)
--entities
loadedTextures = {}
for name, entityDef in pairs(minetest.registered_entities) do
local textures = getTexturesFromEntity(entityDef)
for _, texture in pairs(textures) do
table.insert(loadedTextures, texture)
end
end
airutils.all_entities_textures = filter_texture_names(loadedTextures)
--items
loadedTextures = {}
for name, itemDef in pairs(minetest.registered_items) do
local textures = getTexturesFromItem(itemDef)
for _, texture in pairs(textures) do
table.insert(loadedTextures, texture)
end
end
if airutils.is_minetest then
table.insert(loadedTextures,'bubble.png')
table.insert(loadedTextures,'heart.png')
end
airutils.all_items_textures = filter_texture_names(loadedTextures)
end
-- Function to check if a texture is in the list of loaded textures
function airutils.isTextureLoaded(textureToFind)
if not airutils.all_game_textures then
listLoadedTextures()
end
local textures = airutils.all_game_textures
for _, texture in pairs(textures) do
if texture == textureToFind then
return true
end
end
textures = airutils.all_entities_textures
for _, texture in pairs(textures) do
if texture == textureToFind then
return true
end
end
textures = airutils.all_items_textures
for _, texture in pairs(textures) do
if texture == textureToFind then
return true
end
end
return false
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 360 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 449 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 491 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 455 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 519 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 473 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 477 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 B

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