mirror of
https://github.com/APercy/airutils.git
synced 2025-03-15 00:01:20 +00:00
1406 lines
49 KiB
Lua
1406 lines
49 KiB
Lua
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 .. "hud.lua")
|
|
|
|
local S = airutils.S
|
|
|
|
function airutils.properties_copy(origin_table)
|
|
local tablecopy = {}
|
|
for k, v in pairs(origin_table) do
|
|
tablecopy[k] = v
|
|
end
|
|
return tablecopy
|
|
end
|
|
|
|
function airutils.get_hipotenuse_value(point1, point2)
|
|
return math.sqrt((point1.x - point2.x) ^ 2 + (point1.y - point2.y) ^ 2 + (point1.z - point2.z) ^ 2)
|
|
end
|
|
|
|
function airutils.dot(v1,v2)
|
|
return v1.x*v2.x+v1.y*v2.y+v1.z*v2.z
|
|
end
|
|
|
|
function airutils.sign(n)
|
|
return n>=0 and 1 or -1
|
|
end
|
|
|
|
function airutils.minmax(v,m)
|
|
return math.min(math.abs(v),m)*airutils.sign(v)
|
|
end
|
|
|
|
function airutils.get_gauge_angle(value, initial_angle)
|
|
initial_angle = initial_angle or 90
|
|
local angle = value * 18
|
|
angle = angle - initial_angle
|
|
angle = angle * -1
|
|
return angle
|
|
end
|
|
|
|
local function sit_player(player, name)
|
|
if not player then return end
|
|
if airutils.is_minetest then
|
|
player_api.player_attached[name] = true
|
|
player_api.set_animation(player, "sit")
|
|
elseif airutils.is_mcl then
|
|
mcl_player.player_attached[name] = true
|
|
mcl_player.player_set_animation(player, "sit" , 30)
|
|
airutils.sit(player)
|
|
end
|
|
|
|
-- make the driver sit
|
|
minetest.after(1, function()
|
|
if player then
|
|
--minetest.chat_send_all("okay")
|
|
airutils.sit(player)
|
|
--apply_physics_override(player, {speed=0,gravity=0,jump=0})
|
|
end
|
|
end)
|
|
end
|
|
|
|
-- attach player
|
|
function airutils.attach(self, player, instructor_mode)
|
|
if not player then return end
|
|
if self._needed_licence then
|
|
local can_fly = minetest.check_player_privs(player, self._needed_licence)
|
|
if not can_fly then
|
|
minetest.chat_send_player(player:get_player_name(), core.colorize('#ff0000', S(' >>> You need the priv') .. '"'..self._needed_licence..'" ' .. S('to fly this plane.')))
|
|
return
|
|
end
|
|
end
|
|
|
|
instructor_mode = instructor_mode or false
|
|
local name = player:get_player_name()
|
|
self.driver_name = name
|
|
|
|
-- attach the driver
|
|
local eye_y = 0
|
|
if instructor_mode == true and self._have_copilot and self._passengers[2] == "" then
|
|
eye_y = -4
|
|
--airutils.seat_create(self, 1)
|
|
--airutils.seat_create(self, 2)
|
|
|
|
if not self.co_pilot_seat_base then
|
|
self.co_pilot_seat_base = self._passengers_base[2]
|
|
end
|
|
player:set_attach(self.co_pilot_seat_base, "", {x = 0, y = 0, z = 0}, {x = 0, y = 0, z = 0})
|
|
self._passengers[2] = name
|
|
else
|
|
eye_y = -4
|
|
--airutils.seat_create(self, 1)
|
|
if not self.pilot_seat_base then
|
|
self.pilot_seat_base = self._passengers_base[1]
|
|
end
|
|
player:set_attach(self.pilot_seat_base, "", {x = 0, y = 0, z = 0}, {x = 0, y = 0, z = 0})
|
|
self._passengers[1] = name
|
|
end
|
|
|
|
if airutils.detect_player_api(player) == 1 then
|
|
eye_y = eye_y + 6.5
|
|
end
|
|
if airutils.detect_player_api(player) == 2 then
|
|
eye_y = -4
|
|
end
|
|
|
|
player:set_eye_offset({x = 0, y = eye_y, z = 2}, {x = 0, y = 1, z = -30})
|
|
sit_player(player, name)
|
|
end
|
|
|
|
local function do_attach(self, player, slot)
|
|
if slot == 0 then return end
|
|
if self._passengers[slot] == "" then
|
|
local name = player:get_player_name()
|
|
--minetest.chat_send_all(self.driver_name)
|
|
self._passengers[slot] = name
|
|
--airutils.seat_create(self, slot)
|
|
player:set_attach(self._passengers_base[slot], "", {x = 0, y = 0, z = 0}, {x = 0, y = 0, z = 0})
|
|
|
|
local eye_y = -4
|
|
if airutils.detect_player_api(player) == 1 then
|
|
eye_y = 2.5
|
|
end
|
|
player:set_eye_offset({x = 0, y = eye_y, z = 2}, {x = 0, y = 3, z = -30})
|
|
sit_player(player, name)
|
|
end
|
|
end
|
|
|
|
function airutils.dettachPlayer(self, player)
|
|
local name = self.driver_name
|
|
airutils.setText(self, self._vehicle_name)
|
|
|
|
airutils.remove_hud(player)
|
|
|
|
--self._engine_running = false
|
|
|
|
--check for external attachment of the vehicle
|
|
local extern_attach = self.object:get_attach()
|
|
local extern_ent = nil
|
|
if extern_attach then
|
|
extern_ent = extern_attach:get_luaentity()
|
|
end
|
|
|
|
-- driver clicked the object => driver gets off the vehicle
|
|
self.driver_name = nil
|
|
|
|
-- detach the player
|
|
--player:set_physics_override({speed = 1, jump = 1, gravity = 1, sneak = true})
|
|
if player then
|
|
player:set_detach()
|
|
player:set_eye_offset({x=0,y=0,z=0},{x=0,y=0,z=0})
|
|
if airutils.is_minetest then
|
|
if player_api.player_attached[name] then
|
|
player_api.player_attached[name] = nil
|
|
end
|
|
player_api.set_animation(player, "stand")
|
|
elseif airutils.is_mcl then
|
|
if mcl_player.player_attached[name] then
|
|
mcl_player.player_attached[name] = nil
|
|
end
|
|
mcl_player.player_set_animation(player, "stand")
|
|
end
|
|
end
|
|
self.driver = nil
|
|
--remove_physics_override(player, {speed=1,gravity=1,jump=1})
|
|
|
|
--move the player to the parent ship if any
|
|
if extern_ent then
|
|
if extern_ent.on_rightclick then
|
|
extern_ent.on_rightclick(extern_ent, player)
|
|
end
|
|
end
|
|
end
|
|
|
|
function airutils.check_passenger_is_attached(self, name)
|
|
local is_attached = false
|
|
if self._passenger == name then is_attached = true end
|
|
if is_attached == false then
|
|
local max_occupants = table.getn(self._seats)
|
|
for i = max_occupants,1,-1
|
|
do
|
|
if self._passengers[i] == name then
|
|
is_attached = true
|
|
break
|
|
end
|
|
end
|
|
end
|
|
return is_attached
|
|
end
|
|
|
|
local function attach_copilot(self, name, player, eye_y)
|
|
--airutils.seat_create(self, 2)
|
|
if not self.co_pilot_seat_base or not player then return end
|
|
self.co_pilot = name
|
|
self._passengers[2] = name
|
|
-- attach the driver
|
|
player:set_attach(self.co_pilot_seat_base, "", {x = 0, y = 0, z = 0}, {x = 0, y = 0, z = 0})
|
|
player:set_eye_offset({x = 0, y = eye_y, z = 2}, {x = 0, y = 3, z = -30})
|
|
|
|
sit_player(player, name)
|
|
end
|
|
|
|
-- attach passenger
|
|
function airutils.attach_pax(self, player, is_copilot)
|
|
if not player then return end
|
|
local is_copilot = is_copilot or false
|
|
local name = player:get_player_name()
|
|
|
|
local eye_y = -4
|
|
if airutils.detect_player_api(player) == 1 then
|
|
eye_y = 2.5
|
|
end
|
|
|
|
if is_copilot == true then
|
|
if self.co_pilot == nil then
|
|
attach_copilot(self, name, player, eye_y)
|
|
end
|
|
else
|
|
--randomize the seat
|
|
local max_seats = table.getn(self._seats)
|
|
local crew = 1
|
|
if self._have_copilot and max_seats > 2 then
|
|
crew = crew + 1
|
|
else
|
|
attach_copilot(self, name, player, eye_y)
|
|
return
|
|
end
|
|
|
|
local t = {} -- new array
|
|
for i=1, max_seats - crew do --(the first are for the crew
|
|
t[i] = i
|
|
end
|
|
|
|
for i = 1, #t*2 do
|
|
local a = math.random(#t)
|
|
local b = math.random(#t)
|
|
t[a],t[b] = t[b],t[a]
|
|
end
|
|
|
|
--for i = 1,10,1 do
|
|
local i = 0
|
|
for k,v in ipairs(t) do
|
|
i = t[k] + crew --jump the crew seats
|
|
if self._passengers[i] and self._passengers[i] == "" then
|
|
--minetest.chat_send_all(self.driver_name)
|
|
self._passengers[i] = name
|
|
--airutils.seat_create(self, i)
|
|
player:set_attach(self._passengers_base[i], "", {x = 0, y = 0, z = 0}, {x = 0, y = 0, z = 0})
|
|
player:set_eye_offset({x = 0, y = eye_y, z = 0}, {x = 0, y = 3, z = -30})
|
|
|
|
sit_player(player, name)
|
|
break
|
|
end
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
function airutils.dettach_pax(self, player, is_flying)
|
|
if not player then return end
|
|
is_flying = is_flying or false
|
|
local name = player:get_player_name() --self._passenger
|
|
airutils.remove_hud(player)
|
|
|
|
--check for external attachment of the vehicle
|
|
local extern_attach = self.object:get_attach()
|
|
local extern_ent = nil
|
|
if extern_attach then
|
|
extern_ent = extern_attach:get_luaentity()
|
|
end
|
|
|
|
-- passenger clicked the object => driver gets off the vehicle
|
|
if self.co_pilot == name then
|
|
self.co_pilot = nil
|
|
self._passengers[2] = ""
|
|
else
|
|
local max_seats = table.getn(self._seats)
|
|
for i = max_seats,1,-1
|
|
do
|
|
if self._passengers[i] == name then
|
|
self._passengers[i] = ""
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
-- detach the player
|
|
if player then
|
|
if name == self.driver_name then
|
|
self.driver_name = nil
|
|
end
|
|
|
|
local pos = player:get_pos()
|
|
player:set_detach()
|
|
if is_flying then
|
|
pos.y = pos.y - self.initial_properties.collisionbox[2] - 2
|
|
player:set_pos(pos)
|
|
end
|
|
|
|
if airutils.is_minetest then
|
|
player_api.player_attached[name] = nil
|
|
player_api.set_animation(player, "stand")
|
|
elseif airutils.is_mcl then
|
|
mcl_player.player_attached[name] = nil
|
|
mcl_player.player_set_animation(player, "stand")
|
|
end
|
|
|
|
player:set_eye_offset({x=0,y=0,z=0},{x=0,y=0,z=0})
|
|
--remove_physics_override(player, {speed=1,gravity=1,jump=1})
|
|
|
|
--move the player to the parent ship if any
|
|
if extern_ent then
|
|
if extern_ent.on_rightclick then
|
|
extern_ent.on_rightclick(extern_ent, player)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function airutils.checkAttach(self, player)
|
|
if player then
|
|
local player_attach = player:get_attach()
|
|
if player_attach then
|
|
local max_seats = table.getn(self._seats)
|
|
for i = max_seats,1,-1
|
|
do
|
|
if self._passengers_base[i] then
|
|
if player_attach == self._passengers_base[i] then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
local function spawn_drops(self, pos)
|
|
if self._drops then
|
|
for k,v in pairs(self._drops) do
|
|
--print(k,v)
|
|
for i=1,v do
|
|
minetest.add_item({x=pos.x+math.random()-0.5,y=pos.y,z=pos.z+math.random()-0.5},k)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function airutils.destroy(self, by_name, by_automation)
|
|
by_name = by_name or ""
|
|
by_automation = by_automation or false
|
|
local with_fire = self._enable_fire_explosion
|
|
local owner = self.owner
|
|
if by_name == owner then with_fire = false end
|
|
local pos = self.object:get_pos()
|
|
local rot = self.object:get_rotation()
|
|
local trunk_slots = self._trunk_slots
|
|
local inv_id = self._inv_id
|
|
if pos == nil then return end
|
|
|
|
if owner and self._vehicle_name then
|
|
minetest.log("action", "airutils: The player "..owner.." had it's "..self._vehicle_name.." destroyed at position x="..math.floor(pos.x).." y="..math.floor(pos.y).." z="..math.floor(pos.z))
|
|
else
|
|
minetest.log("action", "airutils: An airplane was destroyed at position x="..math.floor(pos.x).." y="..math.floor(pos.y).." z="..math.floor(pos.z))
|
|
end
|
|
|
|
if self.sound_handle then
|
|
minetest.sound_stop(self.sound_handle)
|
|
self.sound_handle = nil
|
|
end
|
|
|
|
--remove the passengers first
|
|
local max_seats = table.getn(self._seats)
|
|
for i = max_seats,2,-1
|
|
do
|
|
if self._passengers[i] and self._passengers[i] ~= "" then
|
|
local passenger = minetest.get_player_by_name(self._passengers[i])
|
|
if passenger then airutils.dettach_pax(self, passenger) end
|
|
end
|
|
end
|
|
|
|
if self.driver_name then
|
|
-- detach the driver
|
|
local player = minetest.get_player_by_name(self.driver_name)
|
|
airutils.dettachPlayer(self, player)
|
|
end
|
|
|
|
if by_automation == false then
|
|
airutils.add_destruction_effects(pos, 5, with_fire)
|
|
end
|
|
|
|
airutils.seats_destroy(self)
|
|
if self._destroy_parts_method then
|
|
self._destroy_parts_method(self)
|
|
end
|
|
local obj_children = self.object:get_children()
|
|
for _, child in ipairs(obj_children) do
|
|
child:remove()
|
|
end
|
|
|
|
local destroyed_ent = nil
|
|
if by_automation == false then
|
|
if self._destroyed_ent then
|
|
destroyed_ent = self._destroyed_ent
|
|
end
|
|
|
|
--if dont have a destroyed version, destroy the inventory
|
|
if not destroyed_ent then
|
|
airutils.destroy_inventory(self)
|
|
spawn_drops(self, pos)
|
|
else
|
|
if not with_fire then --or by the owner itself
|
|
airutils.destroy_inventory(self)
|
|
spawn_drops(self, pos)
|
|
end
|
|
end
|
|
else
|
|
airutils.destroy_inventory(self)
|
|
end
|
|
|
|
self.object:remove()
|
|
|
|
if airutils.blast_damage == true and with_fire == true and by_automation == false then
|
|
airutils.add_blast_damage(pos, 7, 10)
|
|
if destroyed_ent then
|
|
|
|
local dest_ent = minetest.add_entity(pos, destroyed_ent)
|
|
if dest_ent then
|
|
local ent = dest_ent:get_luaentity()
|
|
if ent then
|
|
ent.owner = owner
|
|
ent._inv_id = inv_id
|
|
ent._trunk_slots = trunk_slots
|
|
ent._game_time = minetest.get_gametime()
|
|
dest_ent:set_yaw(rot.y)
|
|
end
|
|
end
|
|
|
|
end
|
|
end
|
|
end
|
|
|
|
function airutils.testImpact(self, velocity, position)
|
|
if self.hp_max < 0 then --if acumulated damage is greater than 50, adieu
|
|
airutils.destroy(self)
|
|
end
|
|
if velocity == nil then return end
|
|
local impact_speed = 2
|
|
local p = position --self.object:get_pos()
|
|
local collision = false
|
|
if self._last_vel == nil then return end
|
|
local touch_point = self.initial_properties.collisionbox[2]-0.5
|
|
--lets calculate the vertical speed, to avoid the bug on colliding on floor with hard lag
|
|
if math.abs(velocity.y - self._last_vel.y) > impact_speed then
|
|
local noded = airutils.nodeatpos(airutils.pos_shift(p,{y=touch_point}))
|
|
if (noded and noded.drawtype ~= 'airlike') then
|
|
collision = true
|
|
else
|
|
self.object:set_velocity(self._last_vel)
|
|
--self.object:set_acceleration(self._last_accell)
|
|
--self.object:set_velocity(vector.add(velocity, vector.multiply(self._last_accell, self.dtime/8)))
|
|
end
|
|
end
|
|
local impact = math.abs(airutils.get_hipotenuse_value(velocity, self._last_vel))
|
|
local vertical_impact = math.abs(velocity.y - self._last_vel.y)
|
|
|
|
--minetest.chat_send_all('impact: '.. impact .. ' - hp: ' .. self.hp_max)
|
|
if impact > impact_speed then
|
|
--minetest.chat_send_all('impact: '.. impact .. ' - hp: ' .. self.hp_max)
|
|
if self.colinfo then
|
|
collision = self.colinfo.collides
|
|
end
|
|
end
|
|
|
|
if self._last_water_touch == nil then self._last_water_touch = 3 end
|
|
if self._last_water_touch <= 3 then self._last_water_touch = self._last_water_touch + self.dtime end
|
|
if impact > 0.2 and self._longit_speed > 0.6 and self._last_water_touch >=3 then
|
|
local noded = airutils.nodeatpos(airutils.pos_shift(p,{y=touch_point}))
|
|
if (noded and noded.drawtype ~= 'airlike') then
|
|
if noded.drawtype == 'liquid' then
|
|
self._last_water_touch = 0
|
|
minetest.sound_play("airutils_touch_water", {
|
|
--to_player = self.driver_name,
|
|
object = self.object,
|
|
max_hear_distance = 15,
|
|
gain = 1.0,
|
|
fade = 0.0,
|
|
pitch = 1.0,
|
|
}, true)
|
|
return
|
|
end
|
|
end
|
|
end
|
|
|
|
if self._last_touch == nil then self._last_touch = 1 end
|
|
if self._last_touch <= 1 then self._last_touch = self._last_touch + self.dtime end
|
|
if vertical_impact > 1.0 and self._longit_speed > self._min_speed/2 and self._last_touch >= 1 then
|
|
local noded = airutils.nodeatpos(airutils.pos_shift(p,{y=touch_point}))
|
|
if (noded and noded.drawtype ~= 'airlike') and (noded.drawtype ~= 'liquid') then
|
|
self._last_touch = 0
|
|
if not self._ground_friction then self._ground_friction = 0.99 end
|
|
|
|
if self._ground_friction > 0.97 and self.wheels then
|
|
minetest.sound_play("airutils_touch", {
|
|
--to_player = self.driver_name,
|
|
object = self.object,
|
|
max_hear_distance = 15,
|
|
gain = 1.0,
|
|
fade = 0.0,
|
|
pitch = 1.0,
|
|
}, true)
|
|
else
|
|
minetest.sound_play("airutils_collision", {
|
|
--to_player = self.driver_name,
|
|
object = self.object,
|
|
max_hear_distance = 15,
|
|
gain = 1.0,
|
|
fade = 0.0,
|
|
pitch = 1.0,
|
|
}, true)
|
|
end
|
|
end
|
|
end
|
|
|
|
--damage by speed
|
|
if self._speed_not_exceed then
|
|
if self._last_speed_damage_time == nil then self._last_speed_damage_time = 0 end
|
|
self._last_speed_damage_time = self._last_speed_damage_time + self.dtime
|
|
if self._last_speed_damage_time > 2 then self._last_speed_damage_time = 2 end
|
|
if math.abs(self._longit_speed) > self._speed_not_exceed and self._last_speed_damage_time >= 2 then
|
|
self._last_speed_damage_time = 0
|
|
minetest.sound_play("airutils_collision", {
|
|
--to_player = self.driver_name,
|
|
object = self.object,
|
|
max_hear_distance = 15,
|
|
gain = 1.0,
|
|
fade = 0.0,
|
|
pitch = 1.0,
|
|
}, true)
|
|
self.hp_max = self.hp_max - self._damage_by_wind_speed
|
|
if self.driver_name then
|
|
airutils.setText(self, self._vehicle_name)
|
|
end
|
|
if self.hp_max < 0 then --if acumulated damage is greater than 50, adieu
|
|
airutils.destroy(self)
|
|
end
|
|
end
|
|
end
|
|
|
|
if collision then
|
|
local damage = impact/2 --default for basic planes and trainers
|
|
if self._hard_damage then
|
|
damage = impact*3
|
|
--check if the impact was on landing gear area
|
|
--[[if math.abs(impact - vertical_impact) < (impact*0.1) and --vert speed difference less than 10% of total
|
|
math.abs(math.deg(self.object:get_rotation().x)) < 20 and --nose angle between +20 and -20 degrees
|
|
self._longit_speed < (self._min_speed*2) then --longit speed less than the double of min speed
|
|
self._longit_speed > (self._min_speed/2) then --longit speed bigger than the half of min speed
|
|
damage = impact / 2 --if the plane was landing, the damage is mainly on landing gear, so lets reduce the damage
|
|
end]]--
|
|
--end check
|
|
if math.abs(math.deg(self.object:get_rotation().x)) < 20 and --nose angle between +20 and -20 degrees
|
|
self._longit_speed < (self._min_speed*2) then --longit speed less than the double of min speed
|
|
damage = impact / 2 --if the plane was landing, the damage is mainly on landing gear, so lets reduce the damage
|
|
local new_vel = self.object:get_velocity()
|
|
new_vel.y = 0
|
|
self.object:set_velocity(new_vel) --TODO something is causing the plane to explode after a shaking, so I'm reseting the speed until I discover the bug
|
|
end
|
|
end
|
|
|
|
self.hp_max = self.hp_max - damage --subtract the impact value directly to hp meter
|
|
minetest.sound_play(self._collision_sound, {
|
|
--to_player = self.driver_name,
|
|
object = self.object,
|
|
max_hear_distance = 15,
|
|
gain = 1.0,
|
|
fade = 0.0,
|
|
pitch = 1.0,
|
|
}, true)
|
|
|
|
--stop engine
|
|
if damage > 7 then
|
|
self._power_lever = 0
|
|
self._engine_running = false
|
|
end
|
|
|
|
airutils.setText(self, self._vehicle_name)
|
|
|
|
if self.driver_name then
|
|
local player_name = self.driver_name
|
|
|
|
--minetest.chat_send_all('damage: '.. damage .. ' - hp: ' .. self.hp_max)
|
|
if self.hp_max < 0 then --adieu
|
|
airutils.destroy(self)
|
|
end
|
|
|
|
local player = minetest.get_player_by_name(player_name)
|
|
if player then
|
|
if player:get_hp() > 0 then
|
|
local hurt_by_impact_divisor = 0.5 --less is more
|
|
if self.hp_max > 0 then hurt_by_impact_divisor = 4 end
|
|
player:set_hp(player:get_hp()-(damage/hurt_by_impact_divisor))
|
|
end
|
|
end
|
|
if self._passenger ~= nil then
|
|
local passenger = minetest.get_player_by_name(self._passenger)
|
|
if passenger then
|
|
if passenger:get_hp() > 0 then
|
|
passenger:set_hp(passenger:get_hp()-(damage/2))
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
--this method checks for a disconected player who comes back
|
|
function airutils.rescueConnectionFailedPassengers(self)
|
|
if self._disconnection_check_time == nil then self._disconnection_check_time = 1 end
|
|
self._disconnection_check_time = self._disconnection_check_time + self.dtime
|
|
if not self._passengers_base then return end
|
|
local max_seats = table.getn(self._passengers_base)
|
|
if self._disconnection_check_time > 1 then
|
|
--minetest.chat_send_all(dump(self._passengers))
|
|
self._disconnection_check_time = 0
|
|
for i = max_seats,1,-1
|
|
do
|
|
if self._passengers[i] and self._passengers[i] ~= "" then
|
|
local player = minetest.get_player_by_name(self._passengers[i])
|
|
if player then --we have a player!
|
|
if player:get_attach() == nil then
|
|
--if player_api.player_attached[self._passengers[i]] == nil then --but isn't attached?
|
|
--minetest.chat_send_all("okay")
|
|
if player:get_hp() > 0 then
|
|
self._passengers[i] = "" --clear the slot first
|
|
do_attach(self, player, i) --attach
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function airutils.checkattachBug(self)
|
|
-- for some engine error the player can be detached from the submarine, so lets set him attached again
|
|
local have_driver = (self.driver_name ~= nil)
|
|
if have_driver then
|
|
-- attach the driver again
|
|
local player = minetest.get_player_by_name(self.driver_name)
|
|
if player then
|
|
if player:get_hp() > 0 then
|
|
if player:get_attach() == nil then
|
|
--no attach, lets recover
|
|
airutils.attach(self, player, self._instruction_mode)
|
|
return
|
|
end
|
|
else
|
|
--the player is dead, lets drop
|
|
airutils.dettachPlayer(self, player)
|
|
return
|
|
end
|
|
else
|
|
if (self._passenger ~= nil or self.co_pilot ~= nil) and self._command_is_given == false then
|
|
--no pilot?! a passenger is the pilot now
|
|
self._autopilot = false
|
|
airutils.transfer_control(self, true)
|
|
return
|
|
end
|
|
end
|
|
end
|
|
|
|
--force attach here to prevent desyncronization during fly (it happens in some map areas on my world)
|
|
local base_value = 1.0
|
|
if self._seat_check_interval == nil then self._seat_check_interval = base_value end
|
|
self._seat_check_interval = self._seat_check_interval + self.dtime
|
|
|
|
if self._seat_check_interval >= base_value then
|
|
self._seat_check_interval = 0
|
|
local max_seats = table.getn(self._seats)
|
|
for i = max_seats,1,-1
|
|
do
|
|
if self._passengers[i] and self._passengers[i] ~= "" then
|
|
local player = minetest.get_player_by_name(self._passengers[i])
|
|
if player then --we have a player!
|
|
--minetest.chat_send_all(dump(i).." >> "..self._passengers[i].." >> "..dump(self._passengers).." >> instruction: "..dump(self._instruction_mode))
|
|
if self._passengers[i] == self.driver_name and self._instruction_mode then
|
|
player:set_attach(self.pilot_seat_base, "", {x = 0, y = 0, z = 0}, {x = 0, y = 0, z = 0})
|
|
elseif self._passengers[i] == self.co_pilot and self._instruction_mode then
|
|
player:set_attach(self.co_pilot_seat_base, "", {x = 0, y = 0, z = 0}, {x = 0, y = 0, z = 0})
|
|
else
|
|
player:set_attach(self._passengers_base[i], "", {x = 0, y = 0, z = 0}, {x = 0, y = 0, z = 0})
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function airutils.engineSoundPlay(self)
|
|
--sound
|
|
if self.sound_handle then minetest.sound_stop(self.sound_handle) end
|
|
if self.object then
|
|
local pitch_adjust = 0.5 + ((self._power_lever/100)/2)
|
|
self.sound_handle = minetest.sound_play({name = self._engine_sound},
|
|
{object = self.object, gain = 2.0,
|
|
pitch = pitch_adjust,
|
|
max_hear_distance = 15,
|
|
loop = true,})
|
|
end
|
|
end
|
|
|
|
function airutils.engine_set_sound_and_animation(self)
|
|
--minetest.chat_send_all('test1 ' .. dump(self._engine_running) )
|
|
if self._engine_running then
|
|
if self._last_applied_power ~= self._power_lever and not self._autopilot then
|
|
self._last_applied_power = self._power_lever
|
|
if not self._no_propeller then
|
|
self.object:set_animation_frame_speed(60 + self._power_lever)
|
|
end
|
|
airutils.engineSoundPlay(self)
|
|
end
|
|
else
|
|
if self.sound_handle then
|
|
minetest.sound_stop(self.sound_handle)
|
|
self.sound_handle = nil
|
|
self.object:set_animation_frame_speed(0)
|
|
end
|
|
end
|
|
end
|
|
|
|
function airutils.add_paintable_part(self, entity_ref)
|
|
if not self._paintable_parts then self._paintable_parts = {} end
|
|
table.insert(self._paintable_parts, entity_ref:get_luaentity())
|
|
end
|
|
|
|
function airutils.set_param_paint(self, puncher, itmstck, mode)
|
|
mode = mode or 1
|
|
local item_name = ""
|
|
if itmstck then item_name = itmstck:get_name() end
|
|
|
|
if item_name == "automobiles_lib:painter" or item_name == "bike:painter" then
|
|
self._skin = ""
|
|
--painting with bike painter
|
|
local meta = itmstck:get_meta()
|
|
local colour = meta:get_string("paint_color")
|
|
|
|
local colstr = self._color
|
|
local colstr_2 = self._color_2
|
|
|
|
if mode == 1 then colstr = colour end
|
|
if mode == 2 then colstr_2 = colour end
|
|
airutils.param_paint(self, colstr, colstr_2)
|
|
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
|
|
self._skin = ""
|
|
--[[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 = self._color
|
|
local colstr_2 = self._color_2
|
|
if mode == 1 then colstr = airutils.colors[color] end
|
|
if mode == 2 then colstr_2 = airutils.colors[color] end
|
|
|
|
--minetest.chat_send_all(color ..' '.. dump(colstr))
|
|
--minetest.chat_send_all(dump(airutils.colors))
|
|
if colstr then
|
|
airutils.param_paint(self, colstr, colstr_2)
|
|
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
|
|
|
|
local function _paint(self, l_textures, colstr, paint_list, mask_associations)
|
|
paint_list = paint_list or self._painting_texture
|
|
mask_associations = mask_associations or self._mask_painting_associations
|
|
|
|
for _, texture in ipairs(l_textures) do
|
|
for i, texture_name in ipairs(paint_list) do --textures list
|
|
local indx = texture:find(texture_name)
|
|
if indx then
|
|
l_textures[_] = texture_name.."^[multiply:".. colstr --paint it normally
|
|
local mask_texture = mask_associations[texture_name] --check if it demands a maks too
|
|
--minetest.chat_send_all(texture_name .. " -> " .. dump(mask_texture))
|
|
if mask_texture then --so it then
|
|
l_textures[_] = "("..l_textures[_]..")^("..texture_name.."^[mask:"..mask_texture..")" --add the mask
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return l_textures
|
|
end
|
|
|
|
local function _set_skin(self, l_textures, paint_list, target_texture, skin)
|
|
skin = skin or self._skin
|
|
paint_list = paint_list or self._painting_texture
|
|
target_texture = target_texture or self._skin_target_texture
|
|
if not target_texture then return l_textures end
|
|
for _, texture in ipairs(l_textures) do
|
|
for i, texture_name in ipairs(paint_list) do --textures list
|
|
local indx = texture:find(target_texture)
|
|
if indx then
|
|
l_textures[_] = l_textures[_].."^"..skin --paint it normally
|
|
end
|
|
end
|
|
end
|
|
return l_textures
|
|
end
|
|
|
|
local function set_prefix(self, l_textures)
|
|
--to reduce cpu processing, put the prefix here
|
|
if airutils._use_signs_api then
|
|
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 3.0)
|
|
end
|
|
end
|
|
end
|
|
return l_textures
|
|
end
|
|
|
|
--painting
|
|
function airutils.param_paint(self, colstr, colstr_2)
|
|
colstr_2 = colstr_2 or colstr
|
|
if not self then return end
|
|
if self._skin ~= nil and self._skin ~= "" then
|
|
local l_textures = self.initial_properties.textures
|
|
l_textures = _set_skin(self, l_textures, self._painting_texture, self._skin_target_texture, self._skin)
|
|
|
|
--to reduce cpu processing, put the prefix here
|
|
l_textures = set_prefix(self, l_textures)
|
|
|
|
self.object:set_properties({textures=l_textures})
|
|
|
|
if self._paintable_parts then --paint individual parts
|
|
for i, part_entity in ipairs(self._paintable_parts) do
|
|
local p_textures = part_entity.initial_properties.textures
|
|
p_textures = _set_skin(part_entity, p_textures, self._painting_texture, self._skin_target_texture, self._skin)
|
|
part_entity.object:set_properties({textures=p_textures})
|
|
end
|
|
end
|
|
return
|
|
end
|
|
|
|
if colstr then
|
|
self._color = colstr
|
|
self._color_2 = colstr_2
|
|
local l_textures = self.initial_properties.textures
|
|
|
|
--to reduce cpu processing, put the prefix here
|
|
l_textures = set_prefix(self, l_textures)
|
|
|
|
l_textures = _paint(self, l_textures, colstr) --paint the main plane
|
|
l_textures = _paint(self, l_textures, colstr_2, self._painting_texture_2) --paint the main plane
|
|
self.object:set_properties({textures=l_textures})
|
|
|
|
if self._paintable_parts then --paint individual parts
|
|
for i, part_entity in ipairs(self._paintable_parts) do
|
|
local p_textures = part_entity.initial_properties.textures
|
|
p_textures = _paint(part_entity, p_textures, colstr, self._painting_texture, self._mask_painting_associations)
|
|
p_textures = _paint(part_entity, p_textures, colstr_2, self._painting_texture_2, self._mask_painting_associations)
|
|
part_entity.object:set_properties({textures=p_textures})
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function airutils.paint_with_mask(self, colstr, target_texture, mask_texture, mask_colstr)
|
|
if colstr then
|
|
self._color = colstr
|
|
if mask_colstr then
|
|
self._det_color = mask_colstr
|
|
end
|
|
local l_textures = self.initial_properties.textures
|
|
for _, texture in ipairs(l_textures) do
|
|
local indx = texture:find(target_texture)
|
|
if indx then
|
|
--"("..target_texture.."^[mask:"..mask_texture..")"
|
|
l_textures[_] = "("..target_texture.."^[multiply:".. colstr..")^("..target_texture.."^[mask:"..mask_texture..")"
|
|
end
|
|
end
|
|
self.object:set_properties({textures=l_textures})
|
|
end
|
|
end
|
|
|
|
function airutils.pid_controller(current_value, setpoint, last_error, d_time, kp, ki, kd, integrative)
|
|
kp = kp or 0
|
|
ki = ki or 0.00000000000001
|
|
kd = kd or 0.005
|
|
|
|
local ti = kp/ki
|
|
local td = kd/kp
|
|
local delta_t = d_time
|
|
|
|
local _error = setpoint - current_value
|
|
local derivative = _error - last_error
|
|
--local output = kpv*erro + (kpv/Tiv)*I + kpv*Tdv*((erro - erro_passado)/delta_t);
|
|
if integrative == nil then integrative = 0 end
|
|
integrative = integrative + (((_error + last_error)/delta_t)/2);
|
|
local output = kp*_error + (kp/ti)*integrative + kp * td*((_error - last_error)/delta_t)
|
|
last_error = _error
|
|
return output, last_error
|
|
end
|
|
|
|
function airutils.add_smoke_trail(self, smoke_type)
|
|
smoke_type = smoke_type or 1
|
|
local smoke_texture = "airutils_smoke.png"
|
|
if smoke_type == 2 then
|
|
smoke_texture = "airutils_smoke.png^[multiply:#020202"
|
|
end
|
|
|
|
if self._curr_smoke_type ~= smoke_type then
|
|
self._curr_smoke_type = smoke_type
|
|
if self._smoke_spawner then
|
|
minetest.delete_particlespawner(self._smoke_spawner)
|
|
self._smoke_spawner = nil
|
|
end
|
|
end
|
|
|
|
if self._smoke_spawner == nil then
|
|
self._smoke_spawner = minetest.add_particlespawner({
|
|
amount = 3,
|
|
time = 0,
|
|
--minpos = vector.subtract(pos, radius / 2),
|
|
--maxpos = vector.add(pos, radius / 2),
|
|
minvel = {x = -1, y = -1, z = -1},
|
|
maxvel = {x = 1, y = 5, z = 1},
|
|
minacc = vector.new(),
|
|
maxacc = vector.new(),
|
|
attached = self.object,
|
|
minexptime = 3,
|
|
maxexptime = 5.5,
|
|
minsize = 10,
|
|
maxsize = 15,
|
|
texture = smoke_texture,
|
|
})
|
|
end
|
|
end
|
|
|
|
function airutils.add_destruction_effects(pos, radius, w_fire)
|
|
if pos == nil then return end
|
|
w_fire = w_fire
|
|
if w_fire == nil then w_fire = true end
|
|
local node = airutils.nodeatpos(pos)
|
|
local is_liquid = false
|
|
if (node.drawtype == 'liquid' or node.drawtype == 'flowingliquid') then is_liquid = true end
|
|
|
|
minetest.sound_play("airutils_explode", {
|
|
pos = pos,
|
|
max_hear_distance = 100,
|
|
gain = 2.0,
|
|
fade = 0.0,
|
|
pitch = 1.0,
|
|
}, true)
|
|
if is_liquid == false and w_fire == true then
|
|
minetest.add_particle({
|
|
pos = pos,
|
|
velocity = vector.new(),
|
|
acceleration = vector.new(),
|
|
expirationtime = 0.4,
|
|
size = radius * 10,
|
|
collisiondetection = false,
|
|
vertical = false,
|
|
texture = "airutils_boom.png",
|
|
glow = 15,
|
|
})
|
|
minetest.add_particlespawner({
|
|
amount = 32,
|
|
time = 0.5,
|
|
minpos = vector.subtract(pos, radius / 2),
|
|
maxpos = vector.add(pos, radius / 2),
|
|
minvel = {x = -10, y = -10, z = -10},
|
|
maxvel = {x = 10, y = 10, z = 10},
|
|
minacc = vector.new(),
|
|
maxacc = vector.new(),
|
|
minexptime = 1,
|
|
maxexptime = 2.5,
|
|
minsize = radius * 3,
|
|
maxsize = radius * 5,
|
|
texture = "airutils_boom.png",
|
|
})
|
|
end
|
|
minetest.add_particlespawner({
|
|
amount = 64,
|
|
time = 1.0,
|
|
minpos = vector.subtract(pos, radius / 2),
|
|
maxpos = vector.add(pos, radius / 2),
|
|
minvel = {x = -10, y = -10, z = -10},
|
|
maxvel = {x = 10, y = 10, z = 10},
|
|
minacc = vector.new(),
|
|
maxacc = vector.new(),
|
|
minexptime = 1,
|
|
maxexptime = 2.5,
|
|
minsize = radius * 3,
|
|
maxsize = radius * 5,
|
|
texture = "airutils_smoke.png",
|
|
})
|
|
end
|
|
|
|
function airutils.add_blast_damage(pos, radius, damage_cal)
|
|
if not pos then return end
|
|
radius = radius or 10
|
|
damage_cal = damage_cal or 4
|
|
|
|
local objs = minetest.get_objects_inside_radius(pos, radius)
|
|
for _, obj in pairs(objs) do
|
|
local obj_pos = obj:get_pos()
|
|
local dist = math.max(1, vector.distance(pos, obj_pos))
|
|
local damage = (damage_cal / dist) * radius
|
|
|
|
if obj:is_player() then
|
|
obj:set_hp(obj:get_hp() - damage)
|
|
else
|
|
local luaobj = obj:get_luaentity()
|
|
|
|
-- object might have disappeared somehow
|
|
if luaobj then
|
|
local do_damage = true
|
|
local do_knockback = true
|
|
local entity_drops = {}
|
|
local objdef = minetest.registered_entities[luaobj.name]
|
|
|
|
if objdef and objdef.on_blast then
|
|
do_damage, do_knockback, entity_drops = objdef.on_blast(luaobj, damage)
|
|
end
|
|
|
|
if do_knockback then
|
|
local obj_vel = obj:get_velocity()
|
|
end
|
|
if do_damage then
|
|
obj:punch(obj, 1.0, {
|
|
full_punch_interval = 1.0,
|
|
damage_groups = {fleshy = damage},
|
|
}, nil)
|
|
end
|
|
--[[for _, item in pairs(entity_drops) do
|
|
add_drop(drops, item) -- !!! accessing undefined variable add_drop, drops
|
|
end]]--
|
|
end
|
|
|
|
end
|
|
end
|
|
--lets light some bombs
|
|
if airutils.is_minetest then
|
|
local pr = PseudoRandom(os.time())
|
|
for z = -radius, radius do
|
|
for y = -radius, radius do
|
|
for x = -radius, radius do
|
|
-- remove the nodes
|
|
local r = vector.length(vector.new(x, y, z))
|
|
if (radius * radius) / (r * r) >= (pr:next(80, 125) / 100) then
|
|
local p = {x = pos.x + x, y = pos.y + y, z = pos.z + z}
|
|
local node = minetest.get_node(p).name
|
|
if node == "tnt:tnt" then minetest.set_node(p, {name = "tnt:tnt_burning"}) end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
function airutils.start_engine(self)
|
|
if self._engine_running then
|
|
self._engine_running = false
|
|
self._autopilot = false
|
|
self._power_lever = 0 --zero power
|
|
self._last_applied_power = 0 --zero engine
|
|
elseif self._engine_running == false and self._energy > 0 then
|
|
local curr_health_percent = (self.hp_max * 100)/self._max_plane_hp
|
|
if curr_health_percent > 20 then
|
|
self._engine_running = true
|
|
self._last_applied_power = -1 --send signal to start
|
|
else
|
|
if self.driver_name then
|
|
minetest.chat_send_player(self.driver_name,core.colorize('#ff0000', S(" >>> The engine is damaged, start procedure failed.")))
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
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
|
|
|
|
function airutils.camera_reposition(player, pitch, roll)
|
|
local new_eye_offset = player:get_eye_offset()
|
|
|
|
if roll < -0.4 then roll = -0.4 end
|
|
if roll > 0.4 then roll = 0.4 end
|
|
|
|
local player_properties = player:get_properties()
|
|
|
|
local eye_y = -5
|
|
if airutils.detect_player_api(player) == 1 then
|
|
--minetest.chat_send_all("1")
|
|
eye_y = 0.5
|
|
end
|
|
if airutils.detect_player_api(player) == 2 then
|
|
--minetest.chat_send_all("2")
|
|
eye_y = -5
|
|
end
|
|
|
|
local z, y = airutils.get_xz_from_hipotenuse(0, eye_y, pitch, player_properties.eye_height)
|
|
new_eye_offset.z = z*7
|
|
new_eye_offset.y = y*1.5
|
|
local x, _ = airutils.get_xz_from_hipotenuse(0, eye_y, roll, player_properties.eye_height)
|
|
new_eye_offset.x = -x*15
|
|
|
|
return new_eye_offset
|
|
end
|
|
|
|
function airutils.seats_create(self)
|
|
if self.object then
|
|
local pos = self.object:get_pos()
|
|
self._passengers_base = {}
|
|
self._passengers = {}
|
|
if self._seats then
|
|
local max_seats = table.getn(self._seats)
|
|
for i=1, max_seats do
|
|
self._passengers_base[i] = minetest.add_entity(pos,'airutils:seat_base')
|
|
self._passengers[i] = ""
|
|
if not self._seats_rot then
|
|
self._passengers_base[i]:set_attach(self.object,'',self._seats[i],{x=0,y=0,z=0})
|
|
else
|
|
self._passengers_base[i]:set_attach(self.object,'',self._seats[i],{x=0,y=self._seats_rot[i],z=0})
|
|
end
|
|
end
|
|
|
|
self.pilot_seat_base = self._passengers_base[1] --sets pilot seat reference
|
|
if self._have_copilot and self._passengers_base[2] then
|
|
self.co_pilot_seat_base = self._passengers_base[2] --sets copilot seat reference
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function airutils.seat_create(self, index)
|
|
if self.object then
|
|
local pos = self.object:get_pos()
|
|
if not self._passengers_base then
|
|
self._passengers_base = {}
|
|
if self._seats then
|
|
local max_seats = table.getn(self._seats)
|
|
for i=1, max_seats do
|
|
self._passengers_base[i] = 0
|
|
end
|
|
end
|
|
end
|
|
if self._passengers_base[index] == 0 then
|
|
if self._seats then
|
|
local max_seats = table.getn(self._seats)
|
|
for i=1, max_seats do
|
|
if i == index then
|
|
self._passengers_base[i] = minetest.add_entity(pos,'airutils:seat_base')
|
|
local rot = self._seats_rot[i] or 0
|
|
self._passengers_base[i]:set_attach(self.object,'',self._seats[i],{x=0,y=rot,z=0})
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function airutils.seats_update(self)
|
|
if self.object then
|
|
if self._passengers_base then
|
|
local max_seats = table.getn(self._passengers_base)
|
|
for i=1, max_seats do
|
|
if self._passengers_base[i] then
|
|
if not self._seats_rot then
|
|
self._passengers_base[i]:set_attach(self.object,'',self._seats[i],{x=0,y=0,z=0})
|
|
else
|
|
self._passengers_base[i]:set_attach(self.object,'',self._seats[i],{x=0,y=self._seats_rot[i],z=0})
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function airutils.seats_destroy(self)
|
|
local max_seats = table.getn(self._seats)
|
|
for i=1, max_seats do
|
|
if self._passengers_base and self._passengers_base[i] then
|
|
if self._passengers_base[i] ~= 0 then self._passengers_base[i]:remove() end
|
|
end
|
|
end
|
|
end
|
|
|
|
function airutils.flap_on(self)
|
|
if not self._wing_angle_extra_flaps then
|
|
self._flap = false
|
|
self._wing_configuration = self._wing_angle_of_attack
|
|
return
|
|
end
|
|
|
|
if self._wing_angle_extra_flaps == nil then self._wing_angle_extra_flaps = 0 end --if not, just keep the same as normal angle of attack
|
|
local flap_limit = 15
|
|
if self._flap_limit then flap_limit = self._flap_limit end
|
|
self._wing_configuration = self._wing_angle_of_attack + self._wing_angle_extra_flaps
|
|
if flap_limit >= 0 then
|
|
for i = 0,flap_limit do
|
|
minetest.after(0.02*i, function()
|
|
self.object:set_bone_position("flap.l", {x=0, y=0, z=0}, {x=-i, y=0, z=0})
|
|
self.object:set_bone_position("flap.r", {x=0, y=0, z=0}, {x=-i, y=0, z=0})
|
|
end)
|
|
end
|
|
else
|
|
for i = flap_limit,0 do
|
|
minetest.after(0.02*-i, function()
|
|
self.object:set_bone_position("flap.l", {x=0, y=0, z=0}, {x=-i, y=0, z=0})
|
|
self.object:set_bone_position("flap.r", {x=0, y=0, z=0}, {x=-i, y=0, z=0})
|
|
end)
|
|
end
|
|
--self.object:set_bone_position("flap.l", {x=0, y=0, z=0}, {x=-flap_limit, y=0, z=0})
|
|
--self.object:set_bone_position("flap.r", {x=0, y=0, z=0}, {x=-flap_limit, y=0, z=0})
|
|
end
|
|
end
|
|
|
|
function airutils.flap_off(self)
|
|
self._wing_configuration = self._wing_angle_of_attack
|
|
local flap_limit = 15
|
|
if self._flap_limit then flap_limit = self._flap_limit end
|
|
if flap_limit >= 0 then
|
|
for i = 0,flap_limit do
|
|
minetest.after(0.01*i, function()
|
|
self.object:set_bone_position("flap.l", {x=0, y=0, z=0}, {x=-flap_limit+i, y=0, z=0})
|
|
self.object:set_bone_position("flap.r", {x=0, y=0, z=0}, {x=-flap_limit+i, y=0, z=0})
|
|
end)
|
|
end
|
|
else
|
|
for i = flap_limit,0 do
|
|
minetest.after(0.01*-i, function()
|
|
self.object:set_bone_position("flap.l", {x=0, y=0, z=0}, {x=-flap_limit+i, y=0, z=0})
|
|
self.object:set_bone_position("flap.r", {x=0, y=0, z=0}, {x=-flap_limit+i, y=0, z=0})
|
|
end)
|
|
end
|
|
--self.object:set_bone_position("flap.l", {x=0, y=0, z=0}, {x=0, y=0, z=0})
|
|
--self.object:set_bone_position("flap.r", {x=0, y=0, z=0}, {x=0, y=0, z=0})
|
|
end
|
|
end
|
|
|
|
function airutils.flap_operate(self, player)
|
|
if self._flap == false then
|
|
minetest.chat_send_player(player:get_player_name(), S(">>> Flap down"))
|
|
self._flap = true
|
|
airutils.flap_on(self)
|
|
minetest.sound_play("airutils_collision", {
|
|
object = self.object,
|
|
max_hear_distance = 15,
|
|
gain = 1.0,
|
|
fade = 0.0,
|
|
pitch = 0.5,
|
|
}, true)
|
|
else
|
|
minetest.chat_send_player(player:get_player_name(), S(">>> Flap up"))
|
|
self._flap = false
|
|
airutils.flap_off(self)
|
|
minetest.sound_play("airutils_collision", {
|
|
object = self.object,
|
|
max_hear_distance = 15,
|
|
gain = 1.0,
|
|
fade = 0.0,
|
|
pitch = 0.7,
|
|
}, true)
|
|
end
|
|
end
|
|
|
|
function airutils.landing_lights_operate(self)
|
|
if self._last_light_move == nil then self._last_light_move = 0.15 end
|
|
self._last_light_move = self._last_light_move + self.dtime
|
|
if self._last_light_move > 0.15 then
|
|
self._last_light_move = 0
|
|
if self._land_light == true and self._engine_running == true then
|
|
self._light_active_time = self._light_active_time + self.dtime
|
|
--minetest.chat_send_all(self._light_active_time)
|
|
if self._light_active_time > 24 then self._land_light = false end
|
|
airutils.put_light(self)
|
|
else
|
|
self._land_light = false
|
|
self._light_active_time = 0
|
|
airutils.remove_light(self)
|
|
end
|
|
end
|
|
end
|
|
|
|
function airutils.get_adf_angle(self, pos)
|
|
local adf = 0
|
|
if self._adf == true then
|
|
if airutils.getAngleFromPositions and self._adf_destiny then
|
|
adf = airutils.getAngleFromPositions(pos, self._adf_destiny)
|
|
adf = -(adf + math.deg(self._yaw))
|
|
end
|
|
end
|
|
return adf
|
|
end
|
|
|
|
function airutils.destroyed_save_static_data(self)
|
|
return minetest.serialize(
|
|
{
|
|
stored_owner = self.owner,
|
|
stored_slots = self._trunk_slots,
|
|
stored_inv_id = self._inv_id,
|
|
stored_game_time = self._game_time,
|
|
}
|
|
)
|
|
end
|
|
|
|
function airutils.destroyed_on_activate(self, staticdata, dtime_s)
|
|
if staticdata ~= "" and staticdata ~= nil then
|
|
local data = minetest.deserialize(staticdata) or {}
|
|
self.owner = data.stored_owner
|
|
self._inv_id = data.stored_inv_id
|
|
self._trunk_slots = data.stored_slots
|
|
self._game_time = data.stored_game_time
|
|
end
|
|
|
|
local inv = minetest.get_inventory({type = "detached", name = self._inv_id})
|
|
-- if the game was closed the inventories have to be made anew, instead of just reattached
|
|
if inv then
|
|
self._inv = inv
|
|
end
|
|
|
|
airutils.set_acceleration(self.object,{x=0,y=airutils.gravity,z=0})
|
|
self.object:set_bone_position("elevator", self._elevator_pos, {x=-170, y=0, z=0})
|
|
end
|
|
|
|
local function check_shared_by_time(self)
|
|
local shared_by_time = false
|
|
if self._game_time then
|
|
--check if it was created in the last 20 minutes (1200 seconds)
|
|
if minetest.get_gametime() - self._game_time >= 1200 then shared_by_time = true end
|
|
end
|
|
return shared_by_time
|
|
end
|
|
|
|
function airutils.destroyed_open_inventory(self, clicker)
|
|
if not clicker or not clicker:is_player() then
|
|
return
|
|
end
|
|
|
|
local name = clicker:get_player_name()
|
|
|
|
if self.owner == "" then
|
|
self.owner = name
|
|
end
|
|
|
|
local shared_by_time = check_shared_by_time(self)
|
|
|
|
if name == self.owner or shared_by_time then
|
|
if not self._inv then
|
|
airutils.create_inventory(self, self._trunk_slots)
|
|
end
|
|
airutils.show_vehicle_trunk_formspec(self, clicker, self._trunk_slots)
|
|
else
|
|
minetest.chat_send_player(name, core.colorize('#ff0000', S('>>> You cannot claim this scrap yet, wait some minutes.')))
|
|
end
|
|
end
|
|
|
|
function airutils.destroyed_on_punch(self, puncher, ttime, toolcaps, dir, damage)
|
|
if not puncher or not puncher:is_player() then
|
|
return
|
|
end
|
|
|
|
local name = puncher:get_player_name()
|
|
local shared_by_time = check_shared_by_time(self)
|
|
local pos = self.object:get_pos()
|
|
|
|
local is_admin = minetest.check_player_privs(puncher, {server=true})
|
|
if shared_by_time == false then
|
|
if self.owner and self.owner ~= name and self.owner ~= "" then
|
|
if is_admin == false then return end
|
|
end
|
|
end
|
|
|
|
minetest.sound_play("airutils_collision", {
|
|
object = self.object,
|
|
max_hear_distance = 5,
|
|
gain = 1.0,
|
|
fade = 0.0,
|
|
pitch = 1.0,
|
|
})
|
|
|
|
spawn_drops(self, pos)
|
|
|
|
airutils.destroy_inventory(self)
|
|
self.object:remove()
|
|
end
|