2023-06-11 17:29:08 -03:00
dofile ( minetest.get_modpath ( " airutils " ) .. DIR_DELIM .. " lib_planes " .. DIR_DELIM .. " global_definitions.lua " )
2024-01-27 02:06:23 +01:00
local S = airutils.S
2023-06-11 17:29:08 -03:00
function lib_change_color ( self , colstr )
2023-06-13 12:09:13 -03:00
airutils.param_paint ( self , colstr )
2023-06-11 17:29:08 -03:00
end
function airutils . get_staticdata ( self ) -- unloaded/unloads ... is now saved
return minetest.serialize ( {
--stored_sound_handle = self.sound_handle,
2024-01-23 21:38:27 -03:00
stored_energy = self._energy or 0 ,
stored_owner = self.owner or " " ,
stored_hp = self.hp_max or 10 ,
stored_color = self._color or " #FFFFFF " ,
stored_color_2 = self._color_2 or " #FFFFFF " ,
stored_power_lever = self._power_lever or 0 ,
stored_driver_name = self.driver_name or nil ,
stored_last_accell = self._last_accell or vector.new ( ) ,
stored_inv_id = self._inv_id or nil ,
stored_flap = self._flap or false ,
stored_passengers = self._passengers or { } ,
stored_adf_destiny = self._adf_destiny or vector.new ( ) ,
stored_skin = self._skin or " " ,
2024-02-12 19:41:23 -03:00
stored_vehicle_custom_data = self._vehicle_custom_data or nil ,
stored_ship_name = self._ship_name or " " ,
2024-03-10 13:29:00 -03:00
remove = self._remove or false ,
2023-06-11 17:29:08 -03:00
} )
end
function airutils . on_deactivate ( self )
airutils.save_inventory ( self )
2023-11-15 22:01:47 -03:00
local pos = self.object : get_pos ( )
if airutils.debug_log then
2023-11-15 22:15:51 -03:00
minetest.log ( " action " , " deactivating: " .. self._vehicle_name .. " from " .. self.owner .. " at position " .. math.floor ( pos.x ) .. " , " .. math.floor ( pos.y ) .. " , " .. math.floor ( pos.z ) )
2023-11-15 22:01:47 -03:00
end
2023-06-11 17:29:08 -03:00
end
function airutils . on_activate ( self , staticdata , dtime_s )
2023-11-15 22:01:47 -03:00
local pos = self.object : get_pos ( )
2023-06-11 17:29:08 -03:00
airutils.actfunc ( self , staticdata , dtime_s )
2023-07-04 21:20:39 -03:00
self._flap = false
2023-07-02 15:16:07 -03:00
2023-06-11 17:29:08 -03:00
if staticdata ~= " " and staticdata ~= nil then
local data = minetest.deserialize ( staticdata ) or { }
2024-01-23 21:38:27 -03:00
self._energy = data.stored_energy or 0
self.owner = data.stored_owner or " "
self.hp_max = data.stored_hp or 10
self._color = data.stored_color or " #FFFFFF "
2023-07-13 21:40:40 -03:00
self._color_2 = data.stored_color_2 or data.stored_color --if it has no color 2, now it have!
2024-01-23 21:38:27 -03:00
self._power_lever = data.stored_power_lever or 0
self.driver_name = data.stored_driver_name or nil
self._last_accell = data.stored_last_accell or vector.new ( )
self._inv_id = data.stored_inv_id or nil
if self._wing_angle_extra_flaps then self._flap = data.stored_flap or false end
2023-07-02 15:16:07 -03:00
self._passengers = data.stored_passengers or { }
2023-07-05 21:58:01 -03:00
self._adf_destiny = data.stored_adf_destiny or vector.new ( )
2024-01-23 21:38:27 -03:00
self._skin = data.stored_skin or " "
2024-02-12 19:41:23 -03:00
self._ship_name = data.stored_ship_name or " "
2024-03-10 13:29:00 -03:00
self._remove = data.remove or false
2024-01-23 21:38:27 -03:00
local custom_data = data.stored_vehicle_custom_data or nil
2023-06-20 20:42:35 -03:00
if custom_data then
self._vehicle_custom_data = custom_data
else
-- o macete aqui eh inicializar mesmo que não exista no escopo da entity
self._vehicle_custom_data = { } --initialize it
end
2023-06-11 17:29:08 -03:00
--minetest.debug("loaded: ", self._energy)
if self._engine_running then
self._last_applied_power = - 1 --signal to start
end
2024-03-03 17:50:54 -03:00
2024-03-10 13:29:00 -03:00
if self._remove == true then
2024-03-09 09:47:50 -03:00
airutils.destroy_inventory ( self )
2024-03-03 17:50:54 -03:00
self.object : remove ( )
return
end
2023-06-11 17:29:08 -03:00
end
2024-01-23 21:38:27 -03:00
2023-07-02 16:42:20 -03:00
self._climb_rate = 0
self._yaw = 0
self._roll = 0
self._pitch = 0
2023-07-02 15:16:07 -03:00
2023-11-15 22:01:47 -03:00
if airutils.debug_log then
2023-11-15 22:15:51 -03:00
minetest.log ( " action " , " activating: " .. self._vehicle_name .. " from " .. self.owner .. " at position " .. math.floor ( pos.x ) .. " , " .. math.floor ( pos.y ) .. " , " .. math.floor ( pos.z ) )
2023-11-15 22:01:47 -03:00
end
2023-06-11 17:29:08 -03:00
if self._register_parts_method then
self._register_parts_method ( self )
end
2023-06-18 13:59:31 -03:00
airutils.param_paint ( self , self._color , self._color_2 )
2023-06-11 17:29:08 -03:00
self.object : set_armor_groups ( { immortal = 1 } )
2023-07-08 13:08:34 -03:00
local start_frame = 1
local end_frame = self._anim_frames
if self._anim_start_frame then
start_frame = self._anim_start_frame
end_frame = self._anim_start_frame + self._anim_frames
end
self.object : set_animation ( { x = start_frame , y = end_frame } , 0 , 0 , true )
2023-06-11 17:29:08 -03:00
if self.wheels then
self.wheels : set_animation ( { x = 1 , y = self._anim_frames } , 0 , 0 , true )
end
2024-01-23 21:38:27 -03:00
local inv = nil
if self._inv_id then
inv = minetest.get_inventory ( { type = " detached " , name = self._inv_id } )
end
2023-06-11 17:29:08 -03:00
-- if the game was closed the inventories have to be made anew, instead of just reattached
if not inv then
airutils.create_inventory ( self , self._trunk_slots )
else
2023-11-20 14:36:24 -03:00
self._inv = inv
2023-06-11 17:29:08 -03:00
end
2023-06-18 22:14:27 -03:00
2023-07-02 11:38:36 -03:00
airutils.seats_create ( self )
self._passengers = { }
2023-06-20 20:42:35 -03:00
if not self._vehicle_custom_data then self._vehicle_custom_data = { } end --initialize when it does not exists
2023-07-03 18:37:55 -03:00
if self._flap then airutils.flap_on ( self ) end
2024-01-23 21:38:27 -03:00
if self._vehicle_name then airutils.setText ( self , self._vehicle_name ) end
2023-06-11 17:29:08 -03:00
end
function airutils . on_step ( self , dtime , colinfo )
self.dtime = math.min ( dtime , 0.2 )
self.colinfo = colinfo
self.height = airutils.get_box_height ( self )
-- physics comes first
local vel = self.object : get_velocity ( )
2023-10-14 17:56:14 +02:00
local pos = self.object : get_pos ( )
local props = self.object : get_properties ( )
-- handle visibility on radar
if ( pos and pos.y < airutils.radarMinHeight and props.show_on_minimap ) then
props.show_on_minimap = false
self.object : set_properties ( props )
end
if ( pos and pos.y >= airutils.radarMinHeight and not props.show_on_minimap ) then
props.show_on_minimap = true
self.object : set_properties ( props )
end
2023-11-08 18:49:53 -03:00
if self.isonground and props.show_on_minimap then
2023-10-14 18:20:39 +02:00
props.show_on_minimap = false
2023-10-27 19:42:09 -03:00
self.object : set_properties ( props )
2023-10-14 18:20:39 +02:00
end
2023-06-11 17:29:08 -03:00
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
2023-08-24 20:14:00 -03:00
if self.hp_max <= 0 then
airutils.destroy ( self )
end
2023-06-11 17:29:08 -03:00
self : physics ( )
if self.logic then
self : logic ( )
end
self.lastvelocity = self.object : get_velocity ( )
self.time_total = self.time_total + self.dtime
end
2023-06-29 20:04:13 -03:00
local function ground_pitch ( self , longit_speed , curr_pitch )
2023-11-08 18:49:53 -03:00
local newpitch = curr_pitch
2023-06-29 21:44:38 -03:00
if self._last_longit_speed == nil then self._last_longit_speed = 0 end
-- Estado atual do sistema
if self._current_value == nil then self._current_value = 0 end -- Valor atual do sistema
if self._last_error == nil then self._last_error = 0 end -- Último erro registrado
2023-06-29 20:04:13 -03:00
-- adjust pitch at ground
if math.abs ( longit_speed ) < self._tail_lift_max_speed then
local speed_range = self._tail_lift_max_speed - self._tail_lift_min_speed
local percentage = 1 - ( ( math.abs ( longit_speed ) - self._tail_lift_min_speed ) / speed_range )
if percentage > 1 then percentage = 1 end
if percentage < 0 then percentage = 0 end
local angle = self._tail_angle * percentage
2023-06-29 21:44:38 -03:00
local rad_angle = math.rad ( angle )
if newpitch < rad_angle then newpitch = rad_angle end --ja aproveita o pitch atual se ja estiver cerrto
--[[self._current_value = curr_pitch
local kp = ( longit_speed - self._tail_lift_min_speed ) / 10
local output , last_error = airutils.pid_controller ( self._current_value , rad_angle , self._last_error , self.dtime , kp )
self._last_error = last_error
newpitch = output ] ] --
2023-06-29 20:04:13 -03:00
if newpitch > math.rad ( self._tail_angle ) then newpitch = math.rad ( self._tail_angle ) end --não queremos arrastar o cauda no chão
end
return newpitch
end
2023-06-11 17:29:08 -03:00
function airutils . logic ( self )
local velocity = self.object : get_velocity ( )
2024-03-09 21:30:39 -03:00
local rem_obj = self.object : get_attach ( )
local extern_ent = nil
if rem_obj then
extern_ent = rem_obj : get_luaentity ( )
end
2023-06-11 17:29:08 -03:00
local curr_pos = self.object : get_pos ( )
2023-07-06 20:25:01 -03:00
self._curr_pos = curr_pos --shared
2023-10-27 19:30:18 -03:00
self._last_accel = self.object : get_acceleration ( )
2023-06-11 17:29:08 -03:00
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
2023-07-03 19:22:37 -03:00
local co_pilot = nil
if self.co_pilot and self._have_copilot then co_pilot = minetest.get_player_by_name ( self.co_pilot ) end
2023-06-11 17:29:08 -03:00
2023-11-20 14:36:24 -03:00
--test collision
airutils.testImpact ( self , velocity , curr_pos )
2024-03-12 20:49:26 -03:00
--if self._autoflymode == true then airutils.seats_update(self) end
2024-03-12 20:42:44 -03:00
2023-06-11 17:29:08 -03:00
if player then
local ctrl = player : get_player_control ( )
---------------------
-- change the driver
---------------------
2023-07-06 21:31:15 -03:00
if co_pilot and self._have_copilot and self._last_time_command >= 1 then
2023-06-11 17:29:08 -03:00
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
2023-07-06 21:31:15 -03:00
if ctrl.sneak == true and ctrl.jump == true then
2023-06-11 17:29:08 -03:00
self._last_time_command = 0
--trasnfer the control to student
airutils.transfer_control ( self , true )
2023-07-06 21:31:15 -03:00
end
2023-06-11 17:29:08 -03:00
end
end
-----------
--autopilot
-----------
if self._instruction_mode == false and self._last_time_command >= 1 then
if self._autopilot == 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
self._autopilot = false
2024-01-27 02:06:23 +01:00
minetest.chat_send_player ( self.driver_name , S ( " >>> Autopilot deactivated " ) )
2023-06-11 17:29:08 -03:00
end
else
2023-07-06 21:31:15 -03:00
if ctrl.sneak == true and ctrl.jump == true and self._have_auto_pilot then
2023-06-11 17:29:08 -03:00
self._last_time_command = 0
self._autopilot = true
self._auto_pilot_altitude = curr_pos.y
2024-01-27 02:06:23 +01:00
minetest.chat_send_player ( self.driver_name , core.colorize ( ' #00ff00 ' , S ( " >>> Autopilot on " ) ) )
2023-06-11 17:29:08 -03:00
end
end
end
end
2023-08-24 20:14:00 -03:00
if not self.object : get_acceleration ( ) then return end
2023-06-11 17:29:08 -03:00
local accel_y = self.object : get_acceleration ( ) . y
local rotation = self.object : get_rotation ( )
local yaw = rotation.y
local newyaw = yaw
local pitch = rotation.x
local roll = rotation.z
local newroll = roll
newroll = math.floor ( newroll / 360 )
newroll = newroll * 360
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 )
2024-03-09 21:30:39 -03:00
if extern_ent then
if extern_ent.curr_speed then longit_speed = extern_ent.curr_speed end
--minetest.chat_send_all(dump(longit_speed))
end
2023-06-11 17:29:08 -03:00
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
2023-07-17 10:32:38 -03:00
is_flying = ( not self.colinfo . touching_ground ) and ( self.isinliquid == false )
2024-03-09 21:30:39 -03:00
else
--special routine for automated plane
if extern_ent then
if not extern_ent.on_rightclick then
2024-03-10 11:24:40 -03:00
local touch_point = ( self.initial_properties . collisionbox [ 2 ] ) - 0.5
2024-03-09 21:30:39 -03:00
local node_bellow = airutils.nodeatpos ( airutils.pos_shift ( curr_pos , { y = touch_point } ) )
--minetest.chat_send_all(dump(node_bellow.drawtype))
if ( node_bellow and node_bellow.drawtype ~= ' airlike ' ) then
is_flying = false
end
end
end
2023-06-11 17:29:08 -03:00
end
2024-03-09 21:30:39 -03:00
--minetest.chat_send_all(dump(is_flying))
2023-06-11 17:29:08 -03:00
--if is_flying then minetest.chat_send_all('is flying') end
local is_attached = airutils.checkAttach ( self , player )
2023-06-28 19:48:53 -03:00
if self._indicated_speed == nil then self._indicated_speed = 0 end
2023-06-11 17:29:08 -03:00
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
2023-06-28 19:48:53 -03:00
if self._custom_step_additional_function then
self._custom_step_additional_function ( self )
end
2023-09-14 19:08:51 -03:00
--fix old planes
if not self._flap then self._flap = false end
if not self._wing_configuration then self._wing_configuration = self._wing_angle_of_attack end
2023-07-03 18:37:55 -03:00
if self._wing_configuration == self._wing_angle_of_attack and self._flap then
airutils.flap_on ( self )
end
if self._wing_configuration ~= self._wing_angle_of_attack and self._flap == false then
airutils.flap_off ( self )
end
2023-07-04 21:20:39 -03:00
--landing light
if self._have_landing_lights then
airutils.landing_lights_operate ( self )
end
2023-08-26 14:34:02 -03:00
--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
2023-10-29 20:12:03 -03:00
--adjust elevator pitch (3d model)
self.object : set_bone_position ( " elevator " , self._elevator_pos , { x =- self._elevator_angle * 2 - 90 , y = 0 , z = 0 } )
--adjust rudder
self.object : set_bone_position ( " rudder " , self._rudder_pos , { x = 0 , y = self._rudder_angle , z = 0 } )
--adjust ailerons
if self._aileron_r_pos and self._aileron_l_pos then
local ailerons = self._rudder_angle
if self._invert_ailerons then ailerons = ailerons * - 1 end
self.object : set_bone_position ( " aileron.r " , self._aileron_r_pos , { x =- ailerons - 90 , y = 0 , z = 0 } )
self.object : set_bone_position ( " aileron.l " , self._aileron_l_pos , { x = ailerons - 90 , y = 0 , z = 0 } )
end
2023-08-26 14:34:02 -03:00
2023-10-29 19:50:41 -03:00
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
2023-10-29 20:02:45 -03:00
if self._ground_friction then
2023-11-13 20:37:47 -03:00
if not self.isinliquid then self.object : set_velocity ( { x = 0 , y = airutils.gravity * self.dtime , z = 0 } ) end
2023-10-29 20:02:45 -03:00
end
2023-06-11 17:29:08 -03:00
return
end
2023-06-13 18:02:41 -03:00
--adjust climb indicator
2023-10-26 22:28:38 -03:00
local y_velocity = 0
if self._engine_running or is_flying then y_velocity = velocity.y end
local climb_rate = y_velocity
2023-06-13 18:02:41 -03:00
if climb_rate > 5 then climb_rate = 5 end
if climb_rate < - 5 then
climb_rate = - 5
2023-06-11 17:29:08 -03:00
end
-- pitch
2023-10-26 22:28:38 -03:00
local newpitch = airutils.get_plane_pitch ( y_velocity , longit_speed , self._min_speed , self._angle_of_attack )
2023-06-11 17:29:08 -03:00
2023-09-03 19:49:20 -03:00
--for airplanes with cannard or pendulum wing
local actuator_angle = self._elevator_angle
if self._inverted_pitch_reaction then actuator_angle = - 1 * self._elevator_angle end
2023-06-13 18:02:41 -03:00
--is an stall, force a recover
2023-06-18 12:42:59 -03:00
if longit_speed < ( self._min_speed + 0.5 ) and climb_rate < - 1.5 and is_flying then
if player and self.driver_name then
2023-06-25 19:19:28 -03:00
--minetest.chat_send_player(self.driver_name,core.colorize('#ff0000', " >>> STALL"))
2023-06-18 12:42:59 -03:00
end
2023-06-13 18:02:41 -03:00
self._elevator_angle = 0
2023-09-03 19:49:20 -03:00
actuator_angle = 0
2023-06-18 12:42:59 -03:00
self._angle_of_attack = - 1
2023-06-13 18:02:41 -03:00
newpitch = math.rad ( self._angle_of_attack )
else
--ajustar angulo de ataque
2023-07-17 13:15:14 -03:00
if longit_speed > self._min_speed then
2023-06-13 18:02:41 -03:00
local percentage = math.abs ( ( ( longit_speed * 100 ) / ( self._min_speed + 5 ) ) / 100 )
if percentage > 1.5 then percentage = 1.5 end
2023-09-13 20:25:18 -03:00
2023-09-03 19:49:20 -03:00
self._angle_of_attack = self._wing_angle_of_attack - ( ( actuator_angle / self._elevator_response_attenuation ) * percentage )
2023-06-13 18:02:41 -03:00
2023-09-13 20:25:18 -03:00
--airutils.adjust_attack_angle_by_speed(angle_of_attack, min_angle, max_angle, limit, longit_speed, ideal_step, dtime)
2023-09-13 20:28:27 -03:00
self._angle_of_attack = airutils.adjust_attack_angle_by_speed ( self._angle_of_attack , self._min_attack_angle , self._max_attack_angle , 40 , longit_speed , airutils.ideal_step , self.dtime )
2023-06-13 18:02:41 -03:00
if self._angle_of_attack < self._min_attack_angle then
self._angle_of_attack = self._min_attack_angle
2023-09-03 19:49:20 -03:00
actuator_angle = actuator_angle - 0.2
2023-06-13 18:02:41 -03:00
end --limiting the negative angle]]--
--[[if self._angle_of_attack > self._max_attack_angle then
self._angle_of_attack = self._max_attack_angle
2023-09-03 19:49:20 -03:00
actuator_angle = actuator_angle + 0.2
2023-06-13 18:02:41 -03:00
end --limiting the very high climb angle due to strange behavior]]--]]--
2023-09-03 19:49:20 -03:00
if self._inverted_pitch_reaction then self._elevator_angle = - 1 * actuator_angle end --revert the reversion
2023-06-13 18:02:41 -03:00
end
end
--minetest.chat_send_all(self._angle_of_attack)
2023-06-11 17:29:08 -03:00
-- adjust pitch at ground
2023-07-17 13:15:14 -03:00
if math.abs ( longit_speed ) > self._tail_lift_min_speed and is_flying == false then
2023-06-29 20:04:13 -03:00
newpitch = ground_pitch ( self , longit_speed , newpitch )
2023-06-11 17:29:08 -03:00
else
2023-06-13 18:02:41 -03:00
if math.abs ( longit_speed ) < self._tail_lift_min_speed then
2023-06-11 17:29:08 -03:00
newpitch = math.rad ( self._tail_angle )
end
end
-- new yaw
if math.abs ( self._rudder_angle ) > 1.5 then
2023-07-02 11:38:36 -03:00
local turn_rate = math.rad ( self._yaw_turn_rate )
2023-06-11 17:29:08 -03:00
local yaw_turn = self.dtime * math.rad ( self._rudder_angle ) * turn_rate *
airutils.sign ( longit_speed ) * math.abs ( longit_speed / 2 )
newyaw = yaw + yaw_turn
end
--roll adjust
---------------------------------
local delta = 0.002
if is_flying then
local roll_reference = newyaw
local sdir = minetest.yaw_to_dir ( roll_reference )
local snormal = { x = sdir.z , y = 0 , z =- sdir.x } -- rightside, dot is negative
local prsr = airutils.dot ( snormal , nhdir )
local rollfactor = - 90
local roll_rate = math.rad ( 10 )
newroll = ( prsr * math.rad ( rollfactor ) ) * ( later_speed * roll_rate ) * airutils.sign ( longit_speed )
--[[local rollRotation = -self._rudder_angle * 0.1
newroll = rollRotation ] ] --
--minetest.chat_send_all('newroll: '.. newroll)
else
delta = 0.2
if roll > 0 then
newroll = roll - delta
if newroll < 0 then newroll = 0 end
end
if roll < 0 then
newroll = roll + delta
if newroll > 0 then newroll = 0 end
end
end
---------------------------------
-- end roll
local pilot = player
2023-07-03 19:22:37 -03:00
if self._have_copilot then
if self._command_is_given and co_pilot then
pilot = co_pilot
else
self._command_is_given = false
end
2023-06-11 17:29:08 -03:00
end
------------------------------------------------------
--accell calculation block
------------------------------------------------------
2023-07-03 19:22:37 -03:00
if is_attached or co_pilot then
2023-06-11 17:29:08 -03:00
if self._autopilot ~= true then
accel , stop = airutils.control ( self , self.dtime , hull_direction ,
longit_speed , longit_drag , later_speed , later_drag , accel , pilot , is_flying )
else
accel = airutils.autopilot ( self , self.dtime , hull_direction , longit_speed , accel , curr_pos )
end
end
--end accell
2023-07-02 15:16:07 -03:00
--get disconnected players
airutils.rescueConnectionFailedPassengers ( self )
2023-06-11 17:29:08 -03:00
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
2023-07-17 04:55:29 -03:00
local bob = airutils.minmax ( airutils.dot ( accel , hull_direction ) , 0.02 ) -- vertical bobbing
2023-07-16 20:37:23 -03:00
if bob < 0 then bob = 0 end
2023-06-11 17:29:08 -03:00
accel.y = accel.y + bob
local max_pitch = 6
2023-07-16 20:37:23 -03:00
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
2023-06-11 17:29:08 -03:00
if h_vel_compensation < 0 then h_vel_compensation = 0 end
if h_vel_compensation > max_pitch then h_vel_compensation = max_pitch end
2023-07-16 20:37:23 -03:00
--minetest.chat_send_all(h_vel_compensation)
2023-06-11 17:29:08 -03:00
newpitch = newpitch + ( velocity.y * math.rad ( max_pitch - h_vel_compensation ) )
end
local new_accel = accel
2023-06-29 20:04:13 -03:00
if longit_speed > self._min_speed * 0.66 then
--[[lets do something interesting:
here I ' ll fake the longit speed effect for takeoff, to force the airplane
to use more runway
] ] --
local factorized_longit_speed = longit_speed
if is_flying == false and airutils.quadBezier then
local takeoff_speed = self._min_speed * 4 --so first I'll consider the takeoff speed 4x the minimal flight speed
if longit_speed < takeoff_speed and longit_speed > self._min_speed then -- then if the airplane is above the mininam speed and bellow the take off
local scale = ( longit_speed * 1 ) / takeoff_speed --get a scale of current longit speed relative to takeoff speed
if scale == nil then scale = 0 end --lets avoid any nil
factorized_longit_speed = airutils.quadBezier ( scale , self._min_speed , longit_speed , longit_speed ) --here the magic happens using a bezier curve
--minetest.chat_send_all("factor: " .. factorized_longit_speed .. " - longit: " .. longit_speed .. " - scale: " .. scale)
if factorized_longit_speed < 0 then factorized_longit_speed = 0 end --lets avoid negative numbers
if factorized_longit_speed == nil then factorized_longit_speed = longit_speed end --and nil numbers
end
end
local ceiling = 15000
new_accel = airutils.getLiftAccel ( self , velocity , new_accel , factorized_longit_speed , roll , curr_pos , self._lift , ceiling , self._wing_span )
2023-06-11 17:29:08 -03:00
end
-- end lift
--wind effects
if longit_speed > 1.5 and airutils.wind 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 )
2023-10-10 22:12:23 -03:00
--airutils.set_acceleration(self.object, new_accel)
2023-10-26 20:00:05 -03:00
local limit = ( self._max_speed / self.dtime )
2023-10-25 20:15:13 -03:00
if new_accel.y > limit then new_accel.y = limit end --it isn't a rocket :/
2023-10-26 22:28:38 -03:00
2023-06-11 17:29:08 -03:00
else
if stop == true then
2023-10-29 18:05:38 -03:00
self._last_accell = vector.new ( ) --self.object:get_acceleration()
2023-06-11 17:29:08 -03:00
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
2023-10-29 19:38:44 -03:00
local min_speed_animation = 0.1
if math.abs ( velocity.x ) > min_speed_animation or math.abs ( velocity.z ) > min_speed_animation then
2023-06-11 17:29:08 -03:00
self.wheels : set_animation_frame_speed ( longit_speed * 10 )
else
2024-03-09 21:30:39 -03:00
if extern_ent then
self.wheels : set_animation_frame_speed ( longit_speed * 10 )
else
self.wheels : set_animation_frame_speed ( 0 )
end
2023-06-11 17:29:08 -03:00
end
else
--stop wheels
self.wheels : set_animation_frame_speed ( 0 )
end
end
------------------------------------------------------
-- end accell
------------------------------------------------------
------------------------------------------------------
-- sound and animation
------------------------------------------------------
airutils.engine_set_sound_and_animation ( self )
2023-08-26 14:34:02 -03:00
2023-06-11 17:29:08 -03:00
------------------------------------------------------
--self.object:get_luaentity() --hack way to fix jitter on climb
2023-06-17 19:08:31 -03:00
--GAUGES
2023-06-11 17:29:08 -03:00
--minetest.chat_send_all('rate '.. climb_rate)
local climb_angle = airutils.get_gauge_angle ( climb_rate )
2023-07-02 16:42:20 -03:00
self._climb_rate = climb_rate
2023-06-11 17:29:08 -03:00
local indicated_speed = longit_speed * 0.9
if indicated_speed < 0 then indicated_speed = 0 end
2023-06-25 17:52:16 -03:00
self._indicated_speed = indicated_speed
2023-06-27 22:28:58 -03:00
local speed_angle = airutils.get_gauge_angle ( indicated_speed , - 45 )
2023-06-11 17:29:08 -03:00
2023-06-17 19:08:31 -03:00
--adjust power indicator
2023-06-29 22:00:27 -03:00
local power_indicator_angle = airutils.get_gauge_angle ( self._power_lever / 10 ) + 90
2023-07-02 18:15:18 -03:00
local fuel_in_percent = ( self._energy * 1 ) / self._max_fuel
local energy_indicator_angle = ( 180 * fuel_in_percent ) - 180 --(airutils.get_gauge_angle((self._max_fuel - self._energy)*2)) - 90
2023-06-17 19:08:31 -03:00
2023-06-11 17:29:08 -03:00
if is_attached then
if self._show_hud then
2023-06-29 22:00:27 -03:00
airutils.update_hud ( player , climb_angle , speed_angle , power_indicator_angle , energy_indicator_angle )
2023-06-11 17:29:08 -03:00
else
airutils.remove_hud ( player )
end
end
if is_flying == false then
-- new yaw
local turn_rate = math.rad ( 30 )
local yaw_turn = self.dtime * math.rad ( self._rudder_angle ) * turn_rate *
airutils.sign ( longit_speed ) * math.abs ( longit_speed / 2 )
newyaw = yaw + yaw_turn
end
2023-07-02 17:15:55 -03:00
if player and self._use_camera_relocation then
2023-06-27 20:21:25 -03:00
--minetest.chat_send_all(dump(newroll))
local new_eye_offset = airutils.camera_reposition ( player , newpitch , newroll )
2023-06-25 19:19:28 -03:00
player : set_eye_offset ( new_eye_offset , { x = 0 , y = 1 , z = - 30 } )
end
2023-06-11 17:29:08 -03:00
--apply rotations
self.object : set_rotation ( { x = newpitch , y = newyaw , z = newroll } )
--end
2023-07-08 15:50:29 -03:00
if ( longit_speed / 2 ) > self._max_speed and self._flap == true then
2023-07-02 15:16:07 -03:00
if is_attached and self.driver_name then
2024-01-27 02:06:23 +01:00
minetest.chat_send_player ( self.driver_name , core.colorize ( ' #ff0000 ' , S ( " >>> Flaps retracted due for overspeed " ) ) )
2023-07-02 15:16:07 -03:00
end
self._flap = false
end
2023-06-11 17:29:08 -03:00
-- calculate energy consumption --
airutils.consumptionCalc ( self , accel )
--saves last velocity for collision detection (abrupt stop)
2023-10-27 19:30:18 -03:00
self._last_accel = new_accel
2023-06-11 17:29:08 -03:00
self._last_vel = self.object : get_velocity ( )
2023-06-29 21:44:38 -03:00
self._last_longit_speed = longit_speed
2023-07-02 16:42:20 -03:00
self._yaw = newyaw
self._roll = newroll
self._pitch = newpitch
2023-06-11 17:29:08 -03:00
end
2023-06-18 22:14:27 -03:00
local function damage_vehicle ( self , toolcaps , ttime , damage )
2024-02-08 13:54:43 -03:00
damage = damage or 0
2023-10-01 17:21:48 +02:00
if ( not toolcaps ) then
return
2023-06-18 22:14:27 -03:00
end
2023-11-08 18:49:53 -03:00
local value = toolcaps.damage_groups . fleshy or 0
2023-10-01 17:21:48 +02:00
if ( toolcaps.damage_groups . vehicle ) then
value = toolcaps.damage_groups . vehicle
end
damage = damage + value / 10
self.hp_max = self.hp_max - damage
airutils.setText ( self , self._vehicle_name )
2023-06-18 22:14:27 -03:00
end
2023-06-11 17:29:08 -03:00
function airutils . on_punch ( self , puncher , ttime , toolcaps , dir , damage )
2023-11-15 12:04:13 +01:00
local name = " "
local ppos = { }
if not puncher or not puncher : is_player ( ) then
return
end
if ( puncher : is_player ( ) ) then
name = puncher : get_player_name ( )
ppos = puncher : get_pos ( )
2023-11-15 12:47:40 +01:00
if ( minetest.is_protected ( ppos , name ) and
airutils.protect_in_areas ) then
2023-11-15 12:04:13 +01:00
return
end
end
2023-06-17 19:08:31 -03:00
if self.hp_max <= 0 then
2023-07-02 11:38:36 -03:00
airutils.destroy ( self , name )
2023-11-20 14:36:24 -03:00
return
2023-06-17 19:08:31 -03:00
end
2024-01-23 21:38:27 -03:00
if self._vehicle_name then airutils.setText ( self , self._vehicle_name ) end
2023-06-18 22:14:27 -03:00
2023-11-15 12:04:13 +01:00
if ( string.find ( puncher : get_wielded_item ( ) : get_name ( ) , " rayweapon " ) or
toolcaps.damage_groups . vehicle ) then
damage_vehicle ( self , toolcaps , ttime , damage )
2023-06-18 22:14:27 -03:00
end
2023-06-17 19:08:31 -03:00
2023-06-11 17:29:08 -03:00
local is_admin = false
is_admin = minetest.check_player_privs ( puncher , { server = true } )
if self.owner == nil then
self.owner = name
end
2024-01-23 21:38:27 -03:00
if self.owner and self.owner ~= name and self.owner ~= " " then
if is_admin == false then return end
end
2024-03-03 12:14:03 -03:00
if is_admin == false and minetest.check_player_privs ( puncher , { protection_bypass = false } ) then
if self.driver_name and self.driver_name ~= name then
-- do not allow other players to remove the object while there is a driver
return
end
end
2023-06-11 17:29:08 -03:00
local is_attached = false
2023-06-17 19:08:31 -03:00
local player_attach = puncher : get_attach ( )
if player_attach then
if player_attach ~= self.object then
local slot_attach = player_attach : get_attach ( )
if slot_attach == self.object then is_attached = true end
else
is_attached = true
end
end
2023-06-11 17:29:08 -03:00
if puncher : get_attach ( ) == self.object then is_attached = true end
2023-06-17 19:08:31 -03:00
--if puncher:get_attach() == self.pilot_seat_base then is_attached = true end
2023-06-11 17:29:08 -03:00
local itmstck = puncher : get_wielded_item ( )
local item_name = " "
if itmstck then item_name = itmstck : get_name ( ) end
if is_attached == false then
if airutils.loadFuel ( self , puncher : get_player_name ( ) ) then
return
end
--repair
if ( item_name == " airutils:repair_tool " )
and self._engine_running == false then
2023-06-13 12:09:13 -03:00
if self.hp_max < self._max_plane_hp then
2023-06-11 17:29:08 -03:00
local inventory_item = " default:steel_ingot "
local inv = puncher : get_inventory ( )
if inv : contains_item ( " main " , inventory_item ) then
local stack = ItemStack ( inventory_item .. " 1 " )
inv : remove_item ( " main " , stack )
self.hp_max = self.hp_max + 10
2023-06-13 12:09:13 -03:00
if self.hp_max > self._max_plane_hp then self.hp_max = self._max_plane_hp end
2023-07-08 11:05:44 -03:00
airutils.setText ( self , self._vehicle_name )
2023-06-11 17:29:08 -03:00
else
2024-01-27 02:06:23 +01:00
minetest.chat_send_player ( puncher : get_player_name ( ) , S ( " You need steel ingots in your inventory to perform this repair. " ) )
2023-06-11 17:29:08 -03:00
end
end
return
end
-- deal with painting or destroying
if itmstck then
2023-06-18 13:59:31 -03:00
if airutils.set_param_paint ( self , puncher , itmstck , 1 ) == false then
2023-06-11 17:29:08 -03:00
if not self.driver and toolcaps and toolcaps.damage_groups
2023-08-09 21:13:51 -03:00
and toolcaps.groupcaps and ( toolcaps.groupcaps . choppy or toolcaps.groupcaps . axey_dig ) and item_name ~= airutils.fuel then
2023-06-11 17:29:08 -03:00
--airutils.hurt(self,toolcaps.damage_groups.fleshy - 1)
--airutils.make_sound(self,'hit')
2023-06-18 22:14:27 -03:00
damage_vehicle ( self , toolcaps , ttime , damage )
2023-06-11 17:29:08 -03:00
minetest.sound_play ( self._collision_sound , {
object = self.object ,
max_hear_distance = 5 ,
gain = 1.0 ,
fade = 0.0 ,
pitch = 1.0 ,
} )
2023-07-08 11:05:44 -03:00
airutils.setText ( self , self._vehicle_name )
2023-06-11 17:29:08 -03:00
end
end
end
if self.hp_max <= 0 then
2023-07-02 11:38:36 -03:00
airutils.destroy ( self , name )
2023-06-11 17:29:08 -03:00
end
2023-06-17 19:08:31 -03:00
else
if self._custom_punch_when_attached then self._custom_punch_when_attached ( self , puncher ) end
2023-06-11 17:29:08 -03:00
end
end
function airutils . on_rightclick ( self , clicker )
2023-07-02 11:38:36 -03:00
local message = " "
2023-06-11 17:29:08 -03:00
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
2023-07-02 11:38:36 -03:00
local copilot_name = nil
if self.co_pilot and self._have_copilot then
copilot_name = self.co_pilot
2023-06-11 17:29:08 -03:00
end
2023-07-02 11:38:36 -03:00
local touching_ground , liquid_below = airutils.check_node_below ( self.object , 2.5 )
2023-06-11 17:29:08 -03:00
local is_on_ground = self.isinliquid or touching_ground or liquid_below
local is_under_water = airutils.check_is_under_water ( self.object )
2023-07-02 11:38:36 -03:00
--minetest.chat_send_all('name '.. dump(name) .. ' - pilot: ' .. dump(self.driver_name) .. ' - pax: ' .. dump(copilot_name))
2023-06-11 17:29:08 -03:00
--=========================
2023-07-02 11:38:36 -03:00
-- form to pilot
2023-06-11 17:29:08 -03:00
--=========================
2023-07-02 11:38:36 -03:00
local is_attached = false
local seat = clicker : get_attach ( )
if seat then
local plane = seat : get_attach ( )
if plane == self.object then is_attached = true end
end
2023-06-11 17:29:08 -03:00
if name == self.driver_name then
2023-07-02 11:38:36 -03:00
if is_attached then
local itmstck = clicker : get_wielded_item ( )
local item_name = " "
if itmstck then item_name = itmstck : get_name ( ) end
--adf program function
if ( item_name == " compassgps:cgpsmap_marked " ) then
local meta = minetest.deserialize ( itmstck : get_metadata ( ) )
if meta then
self._adf_destiny = { x = meta [ " x " ] , z = meta [ " z " ] }
end
else
--formspec of the plane
if not self._custom_pilot_formspec then
airutils.pilot_formspec ( name )
else
self._custom_pilot_formspec ( name )
end
2023-08-09 21:13:51 -03:00
airutils.sit ( clicker )
2023-07-02 11:38:36 -03:00
end
2023-06-19 20:12:50 -03:00
else
2023-07-02 11:38:36 -03:00
self.driver_name = nil --error, so clean it
2023-06-19 20:12:50 -03:00
end
2023-06-11 17:29:08 -03:00
--=========================
2023-07-02 11:38:36 -03:00
-- detach copilot
2023-06-11 17:29:08 -03:00
--=========================
2023-07-02 11:38:36 -03:00
elseif name == copilot_name then
2023-07-04 21:53:14 -03:00
if self._command_is_given then
2024-03-12 19:40:41 -03:00
--formspec of the plane
if not self._custom_pilot_formspec then
airutils.pilot_formspec ( name )
else
self._custom_pilot_formspec ( name )
end
2023-07-04 21:53:14 -03:00
else
airutils.pax_formspec ( name )
end
2023-06-11 17:29:08 -03:00
--=========================
-- attach pilot
--=========================
2024-03-10 11:31:30 -03:00
elseif not self.driver_name and not self._autoflymode then
2023-06-11 17:29:08 -03:00
if self.owner == name or minetest.check_player_privs ( clicker , { protection_bypass = true } ) then
2023-07-02 21:56:25 -03:00
local itmstck = clicker : get_wielded_item ( )
local item_name = " "
if itmstck then item_name = itmstck : get_name ( ) end
if itmstck then
if airutils.set_param_paint ( self , clicker , itmstck , 2 ) == true then
return
end
end
2023-07-02 11:38:36 -03:00
if clicker : get_player_control ( ) . aux1 == true then --lets see the inventory
airutils.show_vehicle_trunk_formspec ( self , clicker , self._trunk_slots )
else
--[[if airutils.restricted == "true" and not minetest.check_player_privs(clicker, {flight_licence=true}) then
minetest.show_formspec ( name , " airutils:flightlicence " ,
" size[4,2] " ..
" label[0.0,0.0;Sorry ...] " ..
" label[0.0,0.7;You need a flight licence to fly it.] " ..
" label[0.0,1.0;You must obtain it from server admin.] " ..
" button_exit[1.5,1.9;0.9,0.1;e;Exit] " )
return
end ] ] --
if is_under_water then return end
--remove the passengers first
local max_seats = table.getn ( self._seats )
for i = max_seats , 1 , - 1
do
if self._passengers [ i ] then
local passenger = minetest.get_player_by_name ( self._passengers [ i ] )
if passenger then airutils.dettach_pax ( self , passenger ) end
2023-06-18 13:59:31 -03:00
end
2023-07-02 11:38:36 -03:00
end
2023-06-18 13:59:31 -03:00
2023-07-02 11:38:36 -03:00
--attach player
2023-08-12 14:05:32 -03:00
if clicker : get_player_control ( ) . sneak == true and max_seats > 1 then
2023-07-06 21:31:15 -03:00
-- flight instructor mode
self._instruction_mode = true
2023-07-14 21:08:19 -03:00
self.co_pilot_seat_base = self._passengers_base [ 1 ]
self.pilot_seat_base = self._passengers_base [ 2 ]
airutils.attach ( self , clicker )
2023-07-06 21:31:15 -03:00
else
-- no driver => clicker is new driver
self._instruction_mode = false
2023-07-14 21:08:19 -03:00
self.co_pilot_seat_base = self._passengers_base [ 2 ]
self.pilot_seat_base = self._passengers_base [ 1 ]
2023-07-06 21:31:15 -03:00
airutils.attach ( self , clicker )
end
2023-07-02 11:38:36 -03:00
self._command_is_given = false
2023-06-11 17:29:08 -03:00
end
else
2023-07-02 11:38:36 -03:00
airutils.dettach_pax ( self , clicker )
2024-01-27 02:06:23 +01:00
minetest.chat_send_player ( name , core.colorize ( ' #ff0000 ' , S ( " >>> You aren't the owner of this " .. self.infotext .. " . " ) ) )
2023-06-11 17:29:08 -03:00
end
--=========================
-- attach passenger
--=========================
2023-07-02 11:38:36 -03:00
elseif self.driver_name ~= nil or self._autoflymode == true then
2024-03-09 22:46:11 -03:00
local d_name = self.driver_name
if d_name == nil then d_name = " " end
local player = minetest.get_player_by_name ( d_name )
2024-03-09 22:30:39 -03:00
if player or self._autoflymode == true then
2023-07-02 11:38:36 -03:00
is_attached = airutils.check_passenger_is_attached ( self , name )
if is_attached then
--remove pax
airutils.pax_formspec ( name )
else
--attach normal passenger
airutils.attach_pax ( self , clicker )
end
else
minetest.chat_send_player ( clicker : get_player_name ( ) , message )
end
2023-06-11 17:29:08 -03:00
else
2023-07-02 11:38:36 -03:00
minetest.chat_send_player ( clicker : get_player_name ( ) , message )
2023-06-11 17:29:08 -03:00
end
2023-07-02 11:38:36 -03:00
2023-06-11 17:29:08 -03:00
end
2023-07-02 11:38:36 -03:00